mirror of
https://github.com/myhdl/myhdl.git
synced 2024-12-14 07:44:38 +08:00
removed old dirs
This commit is contained in:
parent
30be175048
commit
3eaae1188b
@ -1 +0,0 @@
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,148 +0,0 @@
|
||||
# This file is part of the myhdl library, a Python package for using
|
||||
# Python as a Hardware Description Language.
|
||||
#
|
||||
# Copyright (C) 2003 Jan Decaluwe
|
||||
#
|
||||
# The myhdl library is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU Lesser General Public License as
|
||||
# published by the Free Software Foundation; either version 2.1 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This library is distributed in the hope that it will be useful, but
|
||||
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
# Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public
|
||||
# License along with this library; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
""" myhdl toVerilog package.
|
||||
|
||||
"""
|
||||
|
||||
__author__ = "Jan Decaluwe <jan@jandecaluwe.com>"
|
||||
__revision__ = "$Revision$"
|
||||
__date__ = "$Date$"
|
||||
|
||||
import inspect
|
||||
from compiler import ast as astNode
|
||||
|
||||
import myhdl
|
||||
from myhdl import *
|
||||
from myhdl import ConversionError
|
||||
from myhdl._util import _flatten
|
||||
from myhdl._unparse import _unparse
|
||||
|
||||
class _error:
|
||||
pass
|
||||
_error.FirstArgType = "first argument should be a classic function"
|
||||
_error.ArgType = "leaf cell type error"
|
||||
_error.NotSupported = "Not supported"
|
||||
_error.TopLevelName = "Result of toVerilog call should be assigned to a top level name"
|
||||
_error.SigMultipleDriven = "Signal has multiple drivers"
|
||||
_error.UndefinedBitWidth = "Signal has undefined bit width"
|
||||
_error.UndrivenSignal = "Signal is not driven"
|
||||
_error.UnusedSignal = "Signal is driven but not used"
|
||||
_error.Requirement = "Requirement violation"
|
||||
_error.UnboundLocal = "Local variable may be referenced before assignment"
|
||||
_error.TypeMismatch = "Type mismatch with earlier assignment"
|
||||
_error.NrBitsMismatch = "Nr of bits mismatch with earlier assignment"
|
||||
_error.IntbvBitWidth = "intbv should have bit width"
|
||||
_error.IntbvSign = "intbv's that can have negative values are not yet supported"
|
||||
_error.TypeInfer = "Can't infer variable type"
|
||||
_error.ReturnTypeMismatch = "Return type mismatch"
|
||||
_error.ReturnNrBitsMismatch = "Returned nr of bits mismatch"
|
||||
_error.ReturnIntbvBitWidth = "Returned intbv instance should have bit width"
|
||||
_error.ReturnTypeInfer = "Can't infer return type"
|
||||
_error.ShadowingSignal = "Port is shadowed by internal signal"
|
||||
_error.FreeVarTypeError = "Free variable should be a Signal or an int"
|
||||
_error.ExtraArguments = "Extra positional or named arguments are not supported"
|
||||
_error.UnsupportedYield = "Unsupported yield statement"
|
||||
_error.UnsupportedListComp = \
|
||||
"Unsupported list comprehension form: should be [intbv()[n:] for i in range(m)]"
|
||||
_error.ListElementAssign = \
|
||||
"Can't assign to list element; use slice assignment to change its value"
|
||||
_error.NotASignal = "Non-local object should be a Signal"
|
||||
_error.UnsupportedType = "Object type is not supported in this context"
|
||||
_error.InconsistentType = "Signal elements should have the same base type"
|
||||
_error.InconsistentBitWidth = "Signal elements should have the same bit width"
|
||||
_error.ListElementNotUnique = "List contains Signals that are not unique to it"
|
||||
|
||||
|
||||
_access = enum("INPUT", "OUTPUT", "INOUT", "UNKNOWN")
|
||||
_kind = enum("NORMAL", "DECLARATION", "ALWAYS", "INITIAL", "ALWAYS_COMB", "SIMPLE_ALWAYS_COMB", "ALWAYS_DECO", "TASK", "REG")
|
||||
_context = enum("BOOLEAN", "YIELD", "PRINT" ,"SIGNED", "UNKNOWN")
|
||||
|
||||
|
||||
class _ConversionMixin(object):
|
||||
|
||||
def getLineNo(self, node):
|
||||
lineno = node.lineno
|
||||
if lineno is None:
|
||||
for n in node.getChildNodes():
|
||||
if n.lineno is not None:
|
||||
lineno = n.lineno
|
||||
break
|
||||
lineno = lineno or 0
|
||||
return lineno
|
||||
|
||||
def getObj(self, node):
|
||||
if hasattr(node, 'obj'):
|
||||
return node.obj
|
||||
return None
|
||||
|
||||
def getTarget(self, node):
|
||||
if hasattr(node, 'target'):
|
||||
return node.target
|
||||
return None
|
||||
|
||||
def getKind(self, node):
|
||||
if hasattr(node, 'kind'):
|
||||
return node.kind
|
||||
return None
|
||||
|
||||
def getEdge(self, node):
|
||||
if hasattr(node, 'edge'):
|
||||
return node.edge
|
||||
return None
|
||||
|
||||
def getValue(self, node):
|
||||
if hasattr(node, 'value'):
|
||||
return node.value
|
||||
return None
|
||||
|
||||
def getVal(self, node):
|
||||
val = eval(_unparse(node), self.ast.symdict)
|
||||
return val
|
||||
|
||||
def raiseError(self, node, kind, msg=""):
|
||||
lineno = self.getLineNo(node)
|
||||
info = "in file %s, line %s:\n " % \
|
||||
(self.ast.sourcefile, self.ast.lineoffset+lineno)
|
||||
raise ConversionError(kind, msg, info)
|
||||
|
||||
def require(self, node, test, msg=""):
|
||||
assert isinstance(node, astNode.Node)
|
||||
if not test:
|
||||
self.raiseError(node, _error.Requirement, msg)
|
||||
|
||||
def visitChildNodes(self, node, *args):
|
||||
for n in node.getChildNodes():
|
||||
self.visit(n, *args)
|
||||
|
||||
|
||||
def _LabelGenerator():
|
||||
i = 1
|
||||
while 1:
|
||||
yield "MYHDL%s" % i
|
||||
i += 1
|
||||
|
||||
_genLabel = _LabelGenerator()
|
||||
|
||||
class _Label(object):
|
||||
def __init__(self, name):
|
||||
self.name = _genLabel.next() + '_' + name
|
||||
self.isActive = False
|
||||
def __str__(self):
|
||||
return str(self.name)
|
@ -1,987 +0,0 @@
|
||||
# This file is part of the myhdl library, a Python package for using
|
||||
# Python as a Hardware Description Language.
|
||||
#
|
||||
# Copyright (C) 2003 Jan Decaluwe
|
||||
#
|
||||
# The myhdl library is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU Lesser General Public License as
|
||||
# published by the Free Software Foundation; either version 2.1 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This library is distributed in the hope that it will be useful, but
|
||||
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
# Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public
|
||||
# License along with this library; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
""" myhdl toVerilog analysis module.
|
||||
|
||||
"""
|
||||
|
||||
__author__ = "Jan Decaluwe <jan@jandecaluwe.com>"
|
||||
__revision__ = "$Revision$"
|
||||
__date__ = "$Date$"
|
||||
|
||||
import inspect
|
||||
import compiler
|
||||
from compiler import ast as astNode
|
||||
from sets import Set
|
||||
from types import GeneratorType, FunctionType, ClassType, MethodType
|
||||
from cStringIO import StringIO
|
||||
import re
|
||||
import __builtin__
|
||||
|
||||
import myhdl
|
||||
from myhdl import *
|
||||
from myhdl import ConversionError
|
||||
from myhdl._unparse import _unparse
|
||||
from myhdl._cell_deref import _cell_deref
|
||||
from myhdl._always_comb import _AlwaysComb
|
||||
from myhdl._always import _Always
|
||||
from myhdl._delay import delay
|
||||
from myhdl._toVerilog import _error, _access, _kind, _context, \
|
||||
_ConversionMixin, _Label
|
||||
from myhdl._extractHierarchy import _isMem, _UserDefinedVerilog
|
||||
from myhdl._Signal import _WaiterList
|
||||
|
||||
myhdlObjects = myhdl.__dict__.values()
|
||||
builtinObjects = __builtin__.__dict__.values()
|
||||
|
||||
|
||||
def _makeName(n, prefixes):
|
||||
if len(prefixes) > 1:
|
||||
# name = '_' + '_'.join(prefixes[1:]) + '_' + n
|
||||
name = '_'.join(prefixes[1:]) + '_' + n
|
||||
else:
|
||||
name = n
|
||||
if '[' in name or ']' in name:
|
||||
name = "\\" + name + ' '
|
||||
## print prefixes
|
||||
## print name
|
||||
return name
|
||||
|
||||
def _analyzeSigs(hierarchy):
|
||||
curlevel = 0
|
||||
siglist = []
|
||||
memlist = []
|
||||
prefixes = []
|
||||
|
||||
for inst in hierarchy:
|
||||
level = inst.level
|
||||
name = inst.name
|
||||
sigdict = inst.sigdict
|
||||
memdict = inst.memdict
|
||||
delta = curlevel - level
|
||||
curlevel = level
|
||||
assert(delta >= -1)
|
||||
if delta == -1:
|
||||
prefixes.append(name)
|
||||
else:
|
||||
prefixes = prefixes[:curlevel-1]
|
||||
prefixes.append(name)
|
||||
assert prefixes[-1] == name
|
||||
for n, s in sigdict.items():
|
||||
if s._name is not None:
|
||||
continue
|
||||
s._name = _makeName(n, prefixes)
|
||||
if not s._nrbits:
|
||||
raise ConversionError(_error.UndefinedBitWidth, s._name)
|
||||
siglist.append(s)
|
||||
# list of signals
|
||||
for n, m in memdict.items():
|
||||
if m.name is not None:
|
||||
continue
|
||||
m.name = _makeName(n, prefixes)
|
||||
memlist.append(m)
|
||||
|
||||
# handle the case where a named signal appears in a list also; such a list
|
||||
# is not declared and references to it in a generator will be flagged as an error
|
||||
for m in memlist:
|
||||
for s in m.mem:
|
||||
if s._name is not None:
|
||||
m.decl = False
|
||||
break
|
||||
if not m.decl:
|
||||
continue
|
||||
for i, s in enumerate(m.mem):
|
||||
s._name = "%s[%s]" % (m.name, i)
|
||||
if not s._nrbits:
|
||||
raise ConversionError(_error.UndefinedBitWidth, s._name)
|
||||
if type(s.val) != type(m.elObj.val):
|
||||
raise ConversionError(_error.InconsistentType, s._name)
|
||||
if s._nrbits != m.elObj._nrbits:
|
||||
raise ConversionError(_error.InconsistentBitWidth, s._name)
|
||||
|
||||
return siglist, memlist
|
||||
|
||||
|
||||
|
||||
def _analyzeGens(top, absnames):
|
||||
genlist = []
|
||||
for g in top:
|
||||
if isinstance(g, _UserDefinedVerilog):
|
||||
ast = g
|
||||
elif isinstance(g, (_AlwaysComb, _Always)):
|
||||
f = g.func
|
||||
s = inspect.getsource(f)
|
||||
# remove decorators
|
||||
s = re.sub(r"@.*", "", s)
|
||||
s = s.lstrip()
|
||||
ast = compiler.parse(s)
|
||||
#print ast
|
||||
ast.sourcefile = inspect.getsourcefile(f)
|
||||
ast.lineoffset = inspect.getsourcelines(f)[1]-1
|
||||
ast.symdict = f.func_globals.copy()
|
||||
ast.callstack = []
|
||||
# handle free variables
|
||||
if f.func_code.co_freevars:
|
||||
for n, c in zip(f.func_code.co_freevars, f.func_closure):
|
||||
obj = _cell_deref(c)
|
||||
if isinstance(g, _AlwaysComb):
|
||||
assert isinstance(obj, (int, long, Signal)) or \
|
||||
_isMem(obj) or isTupleOfInts(obj)
|
||||
ast.symdict[n] = obj
|
||||
ast.name = absnames.get(id(g), str(_Label("BLOCK"))).upper()
|
||||
v = _NotSupportedVisitor(ast)
|
||||
compiler.walk(ast, v)
|
||||
if isinstance(g, _AlwaysComb):
|
||||
v = _AnalyzeAlwaysCombVisitor(ast, g.senslist)
|
||||
else:
|
||||
v = _AnalyzeAlwaysDecoVisitor(ast, g.senslist)
|
||||
compiler.walk(ast, v)
|
||||
else:
|
||||
f = g.gi_frame
|
||||
s = inspect.getsource(f)
|
||||
# remove decorators
|
||||
s = re.sub(r"@.*", "", s)
|
||||
s = s.lstrip()
|
||||
ast = compiler.parse(s)
|
||||
#print ast
|
||||
ast.sourcefile = inspect.getsourcefile(f)
|
||||
ast.lineoffset = inspect.getsourcelines(f)[1]-1
|
||||
ast.symdict = f.f_globals.copy()
|
||||
ast.symdict.update(f.f_locals)
|
||||
ast.callstack = []
|
||||
ast.name = absnames.get(id(g), str(_Label("BLOCK"))).upper()
|
||||
v = _NotSupportedVisitor(ast)
|
||||
compiler.walk(ast, v)
|
||||
v = _AnalyzeBlockVisitor(ast)
|
||||
compiler.walk(ast, v)
|
||||
genlist.append(ast)
|
||||
return genlist
|
||||
|
||||
|
||||
class _NotSupportedVisitor(_ConversionMixin):
|
||||
|
||||
def __init__(self, ast):
|
||||
self.ast = ast
|
||||
self.toplevel = True
|
||||
|
||||
def visitAssList(self, node, *args):
|
||||
self.raiseError(node, _error.NotSupported, "list assignment")
|
||||
def visitAssTuple(self, node, *args):
|
||||
self.raiseError(node, _error.NotSupported, "tuple assignment")
|
||||
def visitBackquote(self, node, *args):
|
||||
self.raiseError(node, _error.NotSupported, "backquote")
|
||||
def visitClass(self, node, *args):
|
||||
self.raiseError(node, _error.NotSupported, "class statement")
|
||||
def visitDict(self, node, *args):
|
||||
self.raiseError(node, _error.NotSupported, "dictionary")
|
||||
def visitDiv(self, node, *args):
|
||||
self.raiseError(node, _error.NotSupported, "true division - consider '//'")
|
||||
def visitEllipsis(self, node, *args):
|
||||
self.raiseError(node, _error.NotSupported, "ellipsis")
|
||||
def visitExec(self, node, *args):
|
||||
self.raiseError(node, _error.NotSupported, "exec statement")
|
||||
def visitExpression(self, node, *args):
|
||||
self.raiseError(node, _error.NotSupported, "Expression node")
|
||||
def visitFrom(self, node, *args):
|
||||
self.raiseError(node, _error.NotSupported, "from statement")
|
||||
def visitGlobal(self, node, *args):
|
||||
self.raiseError(node, _error.NotSupported, "global statement")
|
||||
def visitImport(self, node, *args):
|
||||
self.raiseError(node, _error.NotSupported, "import statement")
|
||||
def visitLambda(self, node, *args):
|
||||
self.raiseError(node, _error.NotSupported, "lambda statement")
|
||||
def visitListComp(self, node, *args):
|
||||
if len(node.quals) > 1:
|
||||
self.raiseError(node, _error.NotSupported, "multiple for statements in list comprehension")
|
||||
self.visitChildNodes(node)
|
||||
def visitListCompIf(self, node, *args):
|
||||
self.raiseError(node, _error.NotSupported, "if statement in list comprehension")
|
||||
def visitList(self, node, *args):
|
||||
self.raiseError(node, _error.NotSupported, "list")
|
||||
def visitSliceObj(self, node):
|
||||
self.raiseError(node, _error.NotSupported, "slice object")
|
||||
def visitTryExcept(self, node, *args):
|
||||
self.raiseError(node, _error.NotSupported, "try-except statement")
|
||||
def visitTryFinally(self, node, *args):
|
||||
self.raiseError(node, _error.NotSupported, "try-finally statement")
|
||||
|
||||
def visitAnd(self, node):
|
||||
self.visitChildNodes(node)
|
||||
|
||||
def visitOr(self, node):
|
||||
self.visitChildNodes(node)
|
||||
|
||||
def visitAssign(self, node, *args):
|
||||
if len(node.nodes) > 1:
|
||||
self.raiseError(node, _error.NotSupported, "multiple assignments")
|
||||
self.visit(node.nodes[0], *args)
|
||||
self.visit(node.expr, *args)
|
||||
|
||||
def visitCallFunc(self, node):
|
||||
if node.star_args:
|
||||
self.raiseError(node, _error.NotSupported, "extra positional arguments")
|
||||
if node.dstar_args:
|
||||
self.raiseError(node, _error.NotSupported, "extra named arguments")
|
||||
f = eval(_unparse(node.node), self.ast.symdict)
|
||||
self.visitChildNodes(node)
|
||||
|
||||
def visitCompare(self, node, *args):
|
||||
if len(node.ops) != 1:
|
||||
self.raiseError(node, _error.NotSupported, "chained comparison")
|
||||
self.visitChildNodes(node, *args)
|
||||
|
||||
def visitFunction(self, node, *args):
|
||||
if node.flags != 0: # check flags
|
||||
self.raiseError(node, _error.NotSupported, "extra positional or named arguments")
|
||||
if not self.toplevel:
|
||||
self.raiseError(node, _error.NotSupported, "embedded function definition")
|
||||
self.toplevel = False
|
||||
self.visitChildNodes(node, *args)
|
||||
|
||||
def visitIf(self, node, *args):
|
||||
node.ignore = False
|
||||
if len(node.tests) == 1 and not node.else_:
|
||||
test = node.tests[0][0]
|
||||
if isinstance(test, compiler.ast.Name):
|
||||
if test.name == '__debug__':
|
||||
node.ignore = True
|
||||
return # skip
|
||||
for test, suite in node.tests:
|
||||
self.visit(test)
|
||||
self.visit(suite)
|
||||
if node.else_:
|
||||
self.visit(node.else_)
|
||||
|
||||
def visitPrintnl(self, node, *args):
|
||||
if node.dest is not None:
|
||||
self.raiseError(node, _error.NotSupported, "printing to a file with >> syntax")
|
||||
self.visitChildNodes(node, *args)
|
||||
|
||||
visitPrint = visitPrintnl
|
||||
|
||||
|
||||
def isTupleOfInts(obj):
|
||||
if not isinstance(obj, tuple):
|
||||
return False
|
||||
for e in obj:
|
||||
if not isinstance(e, (int, long)):
|
||||
return False
|
||||
return True
|
||||
|
||||
def getNrBits(obj):
|
||||
if hasattr(obj, '_nrbits'):
|
||||
return obj._nrbits
|
||||
return None
|
||||
|
||||
def hasType(obj, theType):
|
||||
if isinstance(obj, theType):
|
||||
return True
|
||||
if isinstance(obj, Signal):
|
||||
if isinstance(obj._val, theType):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
class ReferenceStack(list):
|
||||
def push(self):
|
||||
self.append(Set())
|
||||
def add(self, item):
|
||||
self[-1].add(item)
|
||||
def __contains__(self, item):
|
||||
for s in self:
|
||||
if item in s:
|
||||
return True
|
||||
return False
|
||||
|
||||
# auxiliary types to aid type checking
|
||||
## class _EdgeDetector(object):
|
||||
## pass
|
||||
|
||||
class _Ram(object):
|
||||
__slots__ = ['elObj', 'depth']
|
||||
|
||||
|
||||
class _Rom(object):
|
||||
__slots__ = ['rom']
|
||||
def __init__(self, rom):
|
||||
self.rom = rom
|
||||
|
||||
|
||||
def _isNegative(obj):
|
||||
if hasattr(obj, '_min') and (obj._min is not None) and (obj._min < 0):
|
||||
return True
|
||||
if isinstance(obj, (int, long)) and obj < 0:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
class _AnalyzeVisitor(_ConversionMixin):
|
||||
|
||||
def __init__(self, ast):
|
||||
ast.sigdict = {}
|
||||
ast.vardict = {}
|
||||
ast.inputs = Set()
|
||||
ast.outputs = Set()
|
||||
ast.argnames = []
|
||||
ast.kind = None
|
||||
ast.hasYield = 0
|
||||
ast.hasRom = False
|
||||
ast.hasPrint = False
|
||||
self.ast = ast
|
||||
self.labelStack = []
|
||||
self.refStack = ReferenceStack()
|
||||
self.globalRefs = Set()
|
||||
|
||||
|
||||
def binaryOp(self, node, *args):
|
||||
self.visit(node.left)
|
||||
self.visit(node.right)
|
||||
node.obj = int()
|
||||
node.signed = node.left.signed or node.right.signed
|
||||
visitAdd = binaryOp
|
||||
visitFloorDiv = binaryOp
|
||||
visitLeftShift = binaryOp
|
||||
visitMul = binaryOp
|
||||
visitPower = binaryOp
|
||||
visitMod = binaryOp
|
||||
visitRightShift = binaryOp
|
||||
visitSub = binaryOp
|
||||
|
||||
def multiBitOp(self, node, *args):
|
||||
node.signed = False
|
||||
for n in node.nodes:
|
||||
self.visit(n)
|
||||
if n.signed:
|
||||
node.signed = True
|
||||
node.obj = None
|
||||
for n in node.nodes:
|
||||
if node.obj is None:
|
||||
node.obj = n.obj
|
||||
elif isinstance(node.obj, type(n.obj)):
|
||||
node.obj = n.obj
|
||||
def visitBitand(self, node, *args):
|
||||
self.multiBitOp(node, *args)
|
||||
def visitBitor(self, node, *args):
|
||||
self.multiBitOp(node, *args)
|
||||
def visitBitxor(self, node, *args):
|
||||
self.multiBitOp(node, *args)
|
||||
def multiLogicalOp(self, node, *args):
|
||||
for n in node.nodes:
|
||||
self.visit(n, *args)
|
||||
for n in node.nodes:
|
||||
if not hasType(n.obj, bool):
|
||||
self.raiseError(node, _error.NotSupported, "non-boolean argument in logical operator")
|
||||
node.obj = bool()
|
||||
def visitAnd(self, node, *args):
|
||||
self.multiLogicalOp(node, *args)
|
||||
def visitOr(self, node, *args):
|
||||
self.multiLogicalOp(node, *args)
|
||||
|
||||
# unaryOp's
|
||||
def visitInvert(self, node, *args):
|
||||
self.visit(node.expr)
|
||||
node.obj = node.expr.obj
|
||||
node.signed = node.expr.signed
|
||||
def visitNot(self, node, *args):
|
||||
self.visit(node.expr)
|
||||
node.obj = bool()
|
||||
node.signed = node.expr.signed
|
||||
def visitUnaryAdd(self, node, *args):
|
||||
self.visit(node.expr)
|
||||
node.obj = int()
|
||||
node.signed = node.expr.signed
|
||||
def visitUnarySub(self, node, *args):
|
||||
self.visit(node.expr)
|
||||
node.obj = int()
|
||||
node.signed = node.expr.signed
|
||||
if isinstance(node.expr, astNode.Const):
|
||||
node.signed = True
|
||||
|
||||
def visitAssAttr(self, node, access=_access.OUTPUT, *args):
|
||||
if node.attrname != 'next':
|
||||
self.raiseError(node, _error.NotSupported, "attribute assignment")
|
||||
self.ast.kind = _kind.TASK
|
||||
self.visit(node.expr, _access.OUTPUT)
|
||||
|
||||
def visitAssign(self, node, access=_access.OUTPUT, *args):
|
||||
target, expr = node.nodes[0], node.expr
|
||||
self.visit(target, _access.OUTPUT)
|
||||
if isinstance(target, astNode.AssName):
|
||||
self.visit(expr, _access.INPUT, _kind.DECLARATION)
|
||||
node.kind = _kind.DECLARATION
|
||||
n = target.name
|
||||
obj = self.getObj(expr)
|
||||
if obj is None:
|
||||
self.raiseError(node, _error.TypeInfer, n)
|
||||
if isinstance(obj, intbv):
|
||||
if len(obj) == 0:
|
||||
self.raiseError(node, _error.IntbvBitWidth, n)
|
||||
## if obj._min < 0:
|
||||
## self.raiseError(node, _error.IntbvSign, n)
|
||||
if obj._min < 0:
|
||||
_signed = True
|
||||
if n in self.ast.vardict:
|
||||
curObj = self.ast.vardict[n]
|
||||
if isinstance(obj, type(curObj)):
|
||||
pass
|
||||
elif isinstance(curObj, type(obj)):
|
||||
self.ast.vardict[n] = obj
|
||||
else:
|
||||
self.raiseError(node, _error.TypeMismatch, n)
|
||||
if getNrBits(obj) != getNrBits(curObj):
|
||||
self.raiseError(node, _error.NrBitsMismatch, n)
|
||||
else:
|
||||
self.ast.vardict[n] = obj
|
||||
else:
|
||||
self.visit(expr, _access.INPUT)
|
||||
|
||||
def visitAssName(self, node, *args):
|
||||
n = node.name
|
||||
if n == "__verilog__":
|
||||
self.raiseError(node, _error.NotSupported,
|
||||
"__verilog__ in generator function")
|
||||
# XXX ?
|
||||
if n in self.globalRefs:
|
||||
self.raiseError(node, _error.UnboundLocal, n)
|
||||
self.refStack.add(n)
|
||||
|
||||
def visitAugAssign(self, node, access=_access.INPUT, *args):
|
||||
self.visit(node.node, _access.INOUT)
|
||||
self.visit(node.expr, _access.INPUT)
|
||||
|
||||
def visitBreak(self, node, *args):
|
||||
self.labelStack[-2].isActive = True
|
||||
|
||||
def visitCallFunc(self, node, *args):
|
||||
self.visit(node.node)
|
||||
for arg in node.args:
|
||||
self.visit(arg, _access.UNKNOWN)
|
||||
argsAreInputs = True
|
||||
f = self.getObj(node.node)
|
||||
node.obj = None
|
||||
node.signed = False
|
||||
if type(f) is type and issubclass(f, intbv):
|
||||
node.obj = self.getVal(node)
|
||||
elif f is len:
|
||||
node.obj = int() # XXX
|
||||
elif f is bool:
|
||||
node.obj = bool()
|
||||
elif f is int:
|
||||
node.obj = int()
|
||||
## elif f in (posedge , negedge):
|
||||
## node.obj = _EdgeDetector()
|
||||
elif f is delay:
|
||||
node.obj = delay(0)
|
||||
elif f in myhdlObjects:
|
||||
pass
|
||||
elif f in builtinObjects:
|
||||
pass
|
||||
elif type(f) is FunctionType:
|
||||
argsAreInputs = False
|
||||
s = inspect.getsource(f)
|
||||
s = s.lstrip()
|
||||
ast = compiler.parse(s)
|
||||
# print ast
|
||||
fname = f.__name__
|
||||
ast.name = _Label(fname)
|
||||
ast.sourcefile = inspect.getsourcefile(f)
|
||||
ast.lineoffset = inspect.getsourcelines(f)[1]-1
|
||||
ast.symdict = f.func_globals.copy()
|
||||
if fname in self.ast.callstack:
|
||||
self.raiseError(node, _error.NotSupported, "Recursive call")
|
||||
ast.callstack = self.ast.callstack[:]
|
||||
ast.callstack.append(fname)
|
||||
# handle free variables
|
||||
if f.func_code.co_freevars:
|
||||
for n, c in zip(f.func_code.co_freevars, f.func_closure):
|
||||
obj = _cell_deref(c)
|
||||
if not isinstance(obj, (int, long, Signal)):
|
||||
self.raiseError(node, _error.FreeVarTypeError, n)
|
||||
ast.symdict[n] = obj
|
||||
v = _NotSupportedVisitor(ast)
|
||||
compiler.walk(ast, v)
|
||||
v = _AnalyzeFuncVisitor(ast, node.args)
|
||||
compiler.walk(ast, v)
|
||||
node.obj = ast.returnObj
|
||||
node.ast = ast
|
||||
for i, arg in enumerate(node.args):
|
||||
if isinstance(arg, astNode.Keyword):
|
||||
n = arg.name
|
||||
else: # Name
|
||||
n = ast.argnames[i]
|
||||
if n in ast.outputs:
|
||||
self.visit(arg, _access.OUTPUT)
|
||||
if n in ast.inputs:
|
||||
self.visit(arg, _access.INPUT)
|
||||
elif type(f) is MethodType:
|
||||
self.raiseError(node,_error.NotSupported, "method call: '%s'" % f.__name__)
|
||||
else:
|
||||
raise AssertionError("Unexpected callable")
|
||||
if argsAreInputs:
|
||||
for arg in node.args:
|
||||
self.visit(arg, _access.INPUT)
|
||||
|
||||
def visitCompare(self, node, *args):
|
||||
node.obj = bool()
|
||||
node.signed = False
|
||||
for n in node.getChildNodes():
|
||||
self.visit(n, *args)
|
||||
if n.signed:
|
||||
node.signed = True
|
||||
op, arg = node.ops[0]
|
||||
## node.expr.target = self.getObj(arg)
|
||||
## arg.target = self.getObj(node.expr)
|
||||
# detect specialized case for the test
|
||||
if op == '==' and isinstance(node.expr, astNode.Name):
|
||||
n = node.expr.name
|
||||
# check wether it can be a case
|
||||
if isinstance(arg.obj, EnumItemType):
|
||||
node.case = (node.expr, arg.obj)
|
||||
# check whether it can be part of an edge check
|
||||
elif n in self.ast.sigdict:
|
||||
sig = self.ast.sigdict[n]
|
||||
v = self.getValue(arg)
|
||||
if v is not None:
|
||||
if v == 0:
|
||||
node.edge = sig.negedge
|
||||
elif v == 1:
|
||||
node.edge = sig.posedge
|
||||
|
||||
|
||||
def visitConst(self, node, *args):
|
||||
node.signed = False
|
||||
if node.value in (0, 1):
|
||||
node.obj = bool(node.value)
|
||||
elif isinstance(node.value, int):
|
||||
node.obj = node.value
|
||||
else:
|
||||
node.obj = None
|
||||
|
||||
def visitContinue(self, node, *args):
|
||||
self.labelStack[-1].isActive = True
|
||||
|
||||
def visitFor(self, node, *args):
|
||||
node.breakLabel = _Label("BREAK")
|
||||
node.loopLabel = _Label("LOOP")
|
||||
self.labelStack.append(node.breakLabel)
|
||||
self.labelStack.append(node.loopLabel)
|
||||
self.refStack.push()
|
||||
self.visit(node.assign)
|
||||
var = node.assign.name
|
||||
self.ast.vardict[var] = int()
|
||||
self.visit(node.list)
|
||||
self.visit(node.body, *args)
|
||||
self.refStack.pop()
|
||||
self.require(node, node.else_ is None, "for-else not supported")
|
||||
self.labelStack.pop()
|
||||
self.labelStack.pop()
|
||||
|
||||
def visitFunction(self, node, *args):
|
||||
raise AssertionError("subclass must implement this")
|
||||
|
||||
def visitGetattr(self, node, *args):
|
||||
self.visit(node.expr, *args)
|
||||
assert isinstance(node.expr, astNode.Name)
|
||||
assert node.expr.name in self.ast.symdict
|
||||
node.obj = None
|
||||
node.signed = False
|
||||
obj = self.ast.symdict[node.expr.name]
|
||||
if isinstance(obj, Signal):
|
||||
if node.attrname == 'posedge':
|
||||
node.obj = obj.posedge
|
||||
elif node.attrname == 'negedge':
|
||||
node.obj = obj.negedge
|
||||
elif node.attrname == 'val':
|
||||
node.obj = obj.val
|
||||
elif isinstance(obj, EnumType):
|
||||
assert hasattr(obj, node.attrname)
|
||||
node.obj = getattr(obj, node.attrname)
|
||||
|
||||
def visitIf(self, node, *args):
|
||||
if node.ignore:
|
||||
return
|
||||
for test, suite in node.tests:
|
||||
self.visit(test, *args)
|
||||
self.refStack.push()
|
||||
self.visit(suite, *args)
|
||||
self.refStack.pop()
|
||||
if node.else_:
|
||||
self.refStack.push()
|
||||
self.visit(node.else_, *args)
|
||||
self.refStack.pop()
|
||||
# check whether the if can be mapped to a (parallel) case
|
||||
node.isCase = node.isFullCase = False
|
||||
test1 = node.tests[0][0]
|
||||
if not hasattr(test1, 'case'):
|
||||
return
|
||||
var1, item1 = test1.case
|
||||
# don't infer a case if there's no elsif test
|
||||
if not node.tests[1:]:
|
||||
return
|
||||
choices = Set()
|
||||
choices.add(item1._index)
|
||||
for test, suite in node.tests[1:]:
|
||||
if not hasattr(test, 'case'):
|
||||
return
|
||||
var, item = test.case
|
||||
if var.name != var1.name or type(item) is not type(item1):
|
||||
return
|
||||
if item._index in choices:
|
||||
return
|
||||
choices.add(item._index)
|
||||
node.isCase = True
|
||||
node.caseVar = var1
|
||||
if (len(choices) == item1._nritems) or (node.else_ is not None):
|
||||
node.isFullCase = True
|
||||
|
||||
def visitListComp(self, node, *args):
|
||||
mem = node.obj = _Ram()
|
||||
self.visit(node.expr, _access.INPUT, _kind.DECLARATION)
|
||||
mem.elObj = self.getObj(node.expr)
|
||||
if not isinstance(mem.elObj, intbv) or not len(mem.elObj) > 0:
|
||||
self.raiseError(node, _error.UnsupportedListComp)
|
||||
cf = node.quals[0].list
|
||||
self.visit(cf)
|
||||
if not isinstance(cf, astNode.CallFunc):
|
||||
self.raiseError(node, _error.UnsupportedListComp)
|
||||
f = self.getObj(cf.node)
|
||||
if f is not range or len(cf.args) != 1:
|
||||
self.raiseError(node, _error.UnsupportedListComp)
|
||||
mem.depth = cf.args[0].obj
|
||||
|
||||
def visitName(self, node, access=_access.INPUT, *args):
|
||||
n = node.name
|
||||
node.obj = None
|
||||
if n not in self.refStack:
|
||||
if n in self.ast.vardict:
|
||||
self.raiseError(node, _error.UnboundLocal, n)
|
||||
self.globalRefs.add(n)
|
||||
if n in self.ast.sigdict:
|
||||
node.obj = sig = self.ast.sigdict[n]
|
||||
if not isinstance(sig, Signal):
|
||||
print "not a signal: %s" % n
|
||||
else:
|
||||
if sig._type is bool:
|
||||
node.edge = sig.posedge
|
||||
if access == _access.INPUT:
|
||||
self.ast.inputs.add(n)
|
||||
elif access == _access.OUTPUT:
|
||||
self.ast.kind = _kind.TASK
|
||||
if n in self.ast.outputs:
|
||||
node.kind = _kind.REG
|
||||
self.ast.outputs.add(n)
|
||||
elif access == _access.UNKNOWN:
|
||||
pass
|
||||
else:
|
||||
raise AssertionError
|
||||
if n in self.ast.vardict:
|
||||
obj = self.ast.vardict[n]
|
||||
if access == _access.INOUT:
|
||||
# upgrade bool to int for augmented assignments
|
||||
if isinstance(obj, bool):
|
||||
obj = int()
|
||||
self.ast.vardict[n] = obj
|
||||
node.obj = obj
|
||||
elif n in self.ast.symdict:
|
||||
node.obj = self.ast.symdict[n]
|
||||
if isTupleOfInts(node.obj):
|
||||
node.obj = _Rom(node.obj)
|
||||
self.ast.hasRom = True
|
||||
elif isinstance(node.obj, int):
|
||||
node.value = node.obj
|
||||
elif n in __builtin__.__dict__:
|
||||
node.obj = __builtin__.__dict__[n]
|
||||
else:
|
||||
pass
|
||||
node.signed = _isNegative(node.obj)
|
||||
## node.target = node.obj
|
||||
|
||||
def visitReturn(self, node, *args):
|
||||
self.raiseError(node, _error.NotSupported, "return statement")
|
||||
|
||||
def visitPrintnl(self, node, *args):
|
||||
self.ast.hasPrint = True
|
||||
self.visitChildNodes(node, *args)
|
||||
|
||||
visitPrint = visitPrintnl
|
||||
|
||||
def visitSlice(self, node, access=_access.INPUT, kind=_kind.NORMAL, *args):
|
||||
node.signed = False
|
||||
self.visit(node.expr, access)
|
||||
node.obj = self.getObj(node.expr)
|
||||
if node.lower:
|
||||
self.visit(node.lower, _access.INPUT)
|
||||
if node.upper:
|
||||
self.visit(node.upper, _access.INPUT)
|
||||
if isinstance(node.obj , intbv):
|
||||
if kind == _kind.DECLARATION:
|
||||
self.require(node.lower, "Expected leftmost index")
|
||||
leftind = self.getVal(node.lower)
|
||||
if node.upper:
|
||||
rightind = self.getVal(node.upper)
|
||||
else:
|
||||
rightind = 0
|
||||
node.obj = node.obj[leftind:rightind]
|
||||
|
||||
|
||||
def visitSubscript(self, node, access=_access.INPUT, *args):
|
||||
node.signed = False
|
||||
self.visit(node.expr, access)
|
||||
assert len(node.subs) == 1
|
||||
self.visit(node.subs[0], _access.INPUT)
|
||||
if isinstance(node.expr.obj, _Ram):
|
||||
if node.flags == 'OP_ASSIGN':
|
||||
self.raiseError(node, _error.ListElementAssign)
|
||||
else:
|
||||
node.obj = node.expr.obj.elObj
|
||||
elif isinstance(node.expr.obj, _Rom):
|
||||
node.obj = int()
|
||||
elif isinstance(node.expr.obj, intbv):
|
||||
node.obj = bool()
|
||||
else:
|
||||
node.obj = bool() # XXX default
|
||||
|
||||
def visitWhile(self, node, *args):
|
||||
node.breakLabel = _Label("BREAK")
|
||||
node.loopLabel = _Label("LOOP")
|
||||
self.labelStack.append(node.breakLabel)
|
||||
self.labelStack.append(node.loopLabel)
|
||||
self.visit(node.test, *args)
|
||||
self.refStack.push()
|
||||
self.visit(node.body, *args)
|
||||
self.refStack.pop()
|
||||
y = node.body.nodes[0]
|
||||
if node.test.obj == True and \
|
||||
isinstance(y, astNode.Yield) and \
|
||||
not self.ast.hasYield > 1 and \
|
||||
not isinstance(self.getObj(y.value), delay):
|
||||
node.kind = _kind.ALWAYS
|
||||
self.require(node, node.else_ is None, "while-else not supported")
|
||||
self.labelStack.pop()
|
||||
self.labelStack.pop()
|
||||
|
||||
def visitYield(self, node, *args):
|
||||
self.ast.hasYield += 1
|
||||
n = node.value
|
||||
self.visit(n)
|
||||
senslist = []
|
||||
if isinstance(n, astNode.Tuple):
|
||||
for n in n.nodes:
|
||||
if not isinstance(n.obj, (Signal, _WaiterList)):
|
||||
self.raiseError(node, _error.UnsupportedYield)
|
||||
senslist.append(n.obj)
|
||||
else:
|
||||
if not isinstance(n.obj, (Signal, _WaiterList, delay)):
|
||||
self.raiseError(node, _error.UnsupportedYield)
|
||||
senslist = [n.obj]
|
||||
node.senslist = senslist
|
||||
|
||||
## def visitModule(self, node, *args):
|
||||
## self.visit(node.node)
|
||||
## for n in self.ast.inputs:
|
||||
## s = self.ast.sigdict[n]
|
||||
## s._read = True
|
||||
|
||||
|
||||
|
||||
class _AnalyzeBlockVisitor(_AnalyzeVisitor):
|
||||
|
||||
def __init__(self, ast):
|
||||
_AnalyzeVisitor.__init__(self, ast)
|
||||
for n, v in self.ast.symdict.items():
|
||||
if isinstance(v, Signal):
|
||||
self.ast.sigdict[n] = v
|
||||
|
||||
def visitFunction(self, node, *args):
|
||||
self.refStack.push()
|
||||
self.visit(node.code)
|
||||
self.ast.kind = _kind.ALWAYS
|
||||
for n in node.code.nodes[:-1]:
|
||||
if not self.getKind(n) == _kind.DECLARATION:
|
||||
self.ast.kind = _kind.INITIAL
|
||||
break
|
||||
if self.ast.kind == _kind.ALWAYS:
|
||||
w = node.code.nodes[-1]
|
||||
if not self.getKind(w) == _kind.ALWAYS:
|
||||
self.ast.kind = _kind.INITIAL
|
||||
self.refStack.pop()
|
||||
|
||||
def visitModule(self, node, *args):
|
||||
self.visit(node.node)
|
||||
for n in self.ast.outputs:
|
||||
s = self.ast.sigdict[n]
|
||||
if s._driven:
|
||||
self.raiseError(node, _error.SigMultipleDriven, n)
|
||||
s._driven = "reg"
|
||||
for n in self.ast.inputs:
|
||||
s = self.ast.sigdict[n]
|
||||
s._read = True
|
||||
|
||||
def visitReturn(self, node, *args):
|
||||
### value should be None
|
||||
if isinstance(node.value, astNode.Const) and node.value.value is None:
|
||||
obj = None
|
||||
elif isinstance(node.value, astNode.Name) and node.value.name == 'None':
|
||||
obj = None
|
||||
else:
|
||||
self.raiseError(node, _error.NotSupported, "return value other than None")
|
||||
|
||||
|
||||
class _AnalyzeAlwaysCombVisitor(_AnalyzeBlockVisitor):
|
||||
|
||||
def __init__(self, ast, senslist):
|
||||
_AnalyzeBlockVisitor.__init__(self, ast)
|
||||
self.ast.senslist = senslist
|
||||
|
||||
def visitFunction(self, node, *args):
|
||||
self.refStack.push()
|
||||
self.visit(node.code)
|
||||
self.ast.kind = _kind.SIMPLE_ALWAYS_COMB
|
||||
for n in node.code.nodes:
|
||||
if isinstance(n, astNode.Assign) and \
|
||||
isinstance(n.nodes[0], astNode.AssAttr) and \
|
||||
self.getKind(n.nodes[0].expr) != _kind.REG:
|
||||
pass
|
||||
else:
|
||||
self.ast.kind = _kind.ALWAYS_COMB
|
||||
return
|
||||
# rom access is expanded into a case statement
|
||||
if self.ast.hasRom:
|
||||
self.ast.kind = _kind.ALWAYS_COMB
|
||||
self.refStack.pop()
|
||||
|
||||
def visitModule(self, node, *args):
|
||||
_AnalyzeBlockVisitor.visitModule(self, node, *args)
|
||||
if self.ast.kind == _kind.SIMPLE_ALWAYS_COMB:
|
||||
for n in self.ast.outputs:
|
||||
s = self.ast.sigdict[n]
|
||||
s._driven = "wire"
|
||||
|
||||
|
||||
class _AnalyzeAlwaysDecoVisitor(_AnalyzeBlockVisitor):
|
||||
|
||||
def __init__(self, ast, senslist):
|
||||
_AnalyzeBlockVisitor.__init__(self, ast)
|
||||
self.ast.senslist = senslist
|
||||
|
||||
def visitFunction(self, node, *args):
|
||||
self.refStack.push()
|
||||
self.visit(node.code)
|
||||
self.ast.kind = _kind.ALWAYS_DECO
|
||||
self.refStack.pop()
|
||||
|
||||
|
||||
|
||||
class _AnalyzeFuncVisitor(_AnalyzeVisitor):
|
||||
|
||||
def __init__(self, ast, args):
|
||||
_AnalyzeVisitor.__init__(self, ast)
|
||||
self.args = args
|
||||
self.ast.hasReturn = False
|
||||
self.ast.returnObj = None
|
||||
|
||||
def visitFunction(self, node, *args):
|
||||
self.refStack.push()
|
||||
argnames = node.argnames
|
||||
for i, arg in enumerate(self.args):
|
||||
if isinstance(arg, astNode.Keyword):
|
||||
n = arg.name
|
||||
self.ast.symdict[n] = self.getObj(arg.expr)
|
||||
else: # Name
|
||||
n = argnames[i]
|
||||
self.ast.symdict[n] = self.getObj(arg)
|
||||
self.ast.argnames.append(n)
|
||||
for n, v in self.ast.symdict.items():
|
||||
if isinstance(v, (Signal, intbv)):
|
||||
self.ast.sigdict[n] = v
|
||||
self.visit(node.code)
|
||||
self.refStack.pop()
|
||||
if self.ast.hasYield:
|
||||
self.raiseError(node, _error.NotSupported,
|
||||
"call to a generator function")
|
||||
if self.ast.kind == _kind.TASK:
|
||||
if self.ast.returnObj is not None:
|
||||
self.raiseError(node, _error.NotSupported,
|
||||
"function with side effects and return value")
|
||||
else:
|
||||
if self.ast.returnObj is None:
|
||||
self.raiseError(node, _error.NotSupported,
|
||||
"pure function without return value")
|
||||
|
||||
|
||||
def visitReturn(self, node, *args):
|
||||
self.visit(node.value, _access.INPUT, _kind.DECLARATION, *args)
|
||||
if isinstance(node.value, astNode.Const) and node.value.value is None:
|
||||
obj = None
|
||||
elif isinstance(node.value, astNode.Name) and node.value.name == 'None':
|
||||
obj = None
|
||||
elif node.value.obj is not None:
|
||||
obj = node.value.obj
|
||||
else:
|
||||
self.raiseError(node, _error.ReturnTypeInfer)
|
||||
if isinstance(obj, intbv) and len(obj) == 0:
|
||||
self.raiseError(node, _error.ReturnIntbvBitWidth)
|
||||
if self.ast.hasReturn:
|
||||
returnObj = self.ast.returnObj
|
||||
if isinstance(obj, type(returnObj)):
|
||||
pass
|
||||
elif isinstance(returnObj, type(obj)):
|
||||
self.ast.returnObj = obj
|
||||
else:
|
||||
self.raiseError(node, _error.ReturnTypeMismatch)
|
||||
if getNrBits(obj) != getNrBits(returnObj):
|
||||
self.raiseError(node, _error.ReturnNrBitsMismatch)
|
||||
else:
|
||||
self.ast.returnObj = obj
|
||||
self.ast.hasReturn = True
|
||||
|
||||
|
||||
def _analyzeTopFunc(func, *args, **kwargs):
|
||||
s = inspect.getsource(func)
|
||||
s = s.lstrip()
|
||||
ast = compiler.parse(s)
|
||||
v = _AnalyzeTopFuncVisitor(*args, **kwargs)
|
||||
compiler.walk(ast, v)
|
||||
return v
|
||||
|
||||
|
||||
class _AnalyzeTopFuncVisitor(object):
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.args = args
|
||||
self.kwargs = kwargs
|
||||
self.name = None
|
||||
self.argdict = {}
|
||||
|
||||
def visitFunction(self, node):
|
||||
self.name = node.name
|
||||
argnames = node.argnames
|
||||
i=-1
|
||||
for i, arg in enumerate(self.args):
|
||||
if isinstance(arg, Signal):
|
||||
n = argnames[i]
|
||||
self.argdict[n] = arg
|
||||
for n in argnames[i+1:]:
|
||||
if n in self.kwargs:
|
||||
arg = self.kwargs[n]
|
||||
if isinstance(arg, Signal):
|
||||
self.argdict[n] = arg
|
||||
self.argnames = [n for n in argnames if n in self.argdict]
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user