1 |
2 |
jvillar |
# This file is part of the myhdl library, a Python package for using
|
2 |
|
|
# Python as a Hardware Description Language.
|
3 |
|
|
#
|
4 |
|
|
# Copyright (C) 2003-2008 Jan Decaluwe
|
5 |
|
|
#
|
6 |
|
|
# The myhdl library is free software; you can redistribute it and/or
|
7 |
|
|
# modify it under the terms of the GNU Lesser General Public License as
|
8 |
|
|
# published by the Free Software Foundation; either version 2.1 of the
|
9 |
|
|
# License, or (at your option) any later version.
|
10 |
|
|
#
|
11 |
|
|
# This library is distributed in the hope that it will be useful, but
|
12 |
|
|
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
13 |
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
14 |
|
|
# Lesser General Public License for more details.
|
15 |
|
|
#
|
16 |
|
|
# You should have received a copy of the GNU Lesser General Public
|
17 |
|
|
# License along with this library; if not, write to the Free Software
|
18 |
|
|
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
19 |
|
|
|
20 |
|
|
""" myhdl toVerilog analysis module.
|
21 |
|
|
|
22 |
|
|
"""
|
23 |
|
|
|
24 |
|
|
|
25 |
|
|
import inspect
|
26 |
|
|
import compiler
|
27 |
|
|
from compiler import ast as astNode
|
28 |
|
|
from sets import Set
|
29 |
|
|
from types import GeneratorType, FunctionType, ClassType, MethodType
|
30 |
|
|
from cStringIO import StringIO
|
31 |
|
|
import re
|
32 |
|
|
import warnings
|
33 |
|
|
import __builtin__
|
34 |
|
|
|
35 |
|
|
import myhdl
|
36 |
|
|
from myhdl import *
|
37 |
|
|
from myhdl import ConversionError
|
38 |
|
|
from myhdl._unparse import _unparse
|
39 |
|
|
from myhdl._cell_deref import _cell_deref
|
40 |
|
|
from myhdl._always_comb import _AlwaysComb
|
41 |
|
|
from myhdl._always import _Always
|
42 |
|
|
from myhdl._delay import delay
|
43 |
|
|
from myhdl.conversion._misc import (_error, _access, _kind, _context,
|
44 |
|
|
_ConversionMixin, _Label, _genUniqueSuffix)
|
45 |
|
|
from myhdl._extractHierarchy import _isMem, _UserCode
|
46 |
|
|
from myhdl._Signal import _WaiterList
|
47 |
|
|
from myhdl._util import _isTupleOfInts
|
48 |
|
|
|
49 |
|
|
myhdlObjects = myhdl.__dict__.values()
|
50 |
|
|
builtinObjects = __builtin__.__dict__.values()
|
51 |
|
|
|
52 |
|
|
_enumTypeSet = set()
|
53 |
|
|
|
54 |
|
|
|
55 |
|
|
def _makeName(n, prefixes):
|
56 |
|
|
if len(prefixes) > 1:
|
57 |
|
|
# name = '_' + '_'.join(prefixes[1:]) + '_' + n
|
58 |
|
|
name = '_'.join(prefixes[1:]) + '_' + n
|
59 |
|
|
else:
|
60 |
|
|
name = n
|
61 |
|
|
if '[' in name or ']' in name:
|
62 |
|
|
name = "\\" + name + ' '
|
63 |
|
|
## print prefixes
|
64 |
|
|
## print name
|
65 |
|
|
return name
|
66 |
|
|
|
67 |
|
|
def _analyzeSigs(hierarchy, hdl='Verilog'):
|
68 |
|
|
curlevel = 0
|
69 |
|
|
siglist = []
|
70 |
|
|
memlist = []
|
71 |
|
|
prefixes = []
|
72 |
|
|
open, close = '[', ']'
|
73 |
|
|
if hdl == 'VHDL':
|
74 |
|
|
open, close = '(', ')'
|
75 |
|
|
|
76 |
|
|
for inst in hierarchy:
|
77 |
|
|
level = inst.level
|
78 |
|
|
name = inst.name
|
79 |
|
|
sigdict = inst.sigdict
|
80 |
|
|
memdict = inst.memdict
|
81 |
|
|
delta = curlevel - level
|
82 |
|
|
curlevel = level
|
83 |
|
|
assert(delta >= -1)
|
84 |
|
|
if delta == -1:
|
85 |
|
|
prefixes.append(name)
|
86 |
|
|
else:
|
87 |
|
|
prefixes = prefixes[:curlevel-1]
|
88 |
|
|
prefixes.append(name)
|
89 |
|
|
assert prefixes[-1] == name
|
90 |
|
|
for n, s in sigdict.items():
|
91 |
|
|
if s._name is not None:
|
92 |
|
|
continue
|
93 |
|
|
s._name = _makeName(n, prefixes)
|
94 |
|
|
if not s._nrbits:
|
95 |
|
|
raise ConversionError(_error.UndefinedBitWidth, s._name)
|
96 |
|
|
siglist.append(s)
|
97 |
|
|
# list of signals
|
98 |
|
|
for n, m in memdict.items():
|
99 |
|
|
if m.name is not None:
|
100 |
|
|
continue
|
101 |
|
|
m.name = _makeName(n, prefixes)
|
102 |
|
|
memlist.append(m)
|
103 |
|
|
|
104 |
|
|
# handle the case where a named signal appears in a list also by giving
|
105 |
|
|
# priority to the list and marking the signals as unused
|
106 |
|
|
for m in memlist:
|
107 |
|
|
if not m._used:
|
108 |
|
|
continue
|
109 |
|
|
m._driven = 'reg'
|
110 |
|
|
for i, s in enumerate(m.mem):
|
111 |
|
|
s._name = "%s%s%s%s" % (m.name, open, i, close)
|
112 |
|
|
s._used = False
|
113 |
|
|
if s._inList:
|
114 |
|
|
raise ConversionError(_error.SignalInMultipleLists, s._name)
|
115 |
|
|
s._inList = True
|
116 |
|
|
if not s._nrbits:
|
117 |
|
|
raise ConversionError(_error.UndefinedBitWidth, s._name)
|
118 |
|
|
if type(s.val) != type(m.elObj.val):
|
119 |
|
|
raise ConversionError(_error.InconsistentType, s._name)
|
120 |
|
|
if s._nrbits != m.elObj._nrbits:
|
121 |
|
|
raise ConversionError(_error.InconsistentBitWidth, s._name)
|
122 |
|
|
|
123 |
|
|
return siglist, memlist
|
124 |
|
|
|
125 |
|
|
|
126 |
|
|
|
127 |
|
|
def _analyzeGens(top, absnames):
|
128 |
|
|
genlist = []
|
129 |
|
|
for g in top:
|
130 |
|
|
if isinstance(g, _UserCode):
|
131 |
|
|
ast = g
|
132 |
|
|
elif isinstance(g, (_AlwaysComb, _Always)):
|
133 |
|
|
f = g.func
|
134 |
|
|
s = inspect.getsource(f)
|
135 |
|
|
# remove decorators
|
136 |
|
|
s = re.sub(r"@.*", "", s)
|
137 |
|
|
s = s.lstrip()
|
138 |
|
|
ast = compiler.parse(s)
|
139 |
|
|
# print ast
|
140 |
|
|
ast.sourcefile = inspect.getsourcefile(f)
|
141 |
|
|
ast.lineoffset = inspect.getsourcelines(f)[1]-1
|
142 |
|
|
ast.symdict = f.func_globals.copy()
|
143 |
|
|
ast.callstack = []
|
144 |
|
|
# handle free variables
|
145 |
|
|
if f.func_code.co_freevars:
|
146 |
|
|
for n, c in zip(f.func_code.co_freevars, f.func_closure):
|
147 |
|
|
obj = _cell_deref(c)
|
148 |
|
|
if isinstance(g, _AlwaysComb):
|
149 |
|
|
print type(obj)
|
150 |
|
|
assert isinstance(obj, (int, long, Signal)) or \
|
151 |
|
|
_isMem(obj) or _isTupleOfInts(obj)
|
152 |
|
|
ast.symdict[n] = obj
|
153 |
|
|
ast.name = absnames.get(id(g), str(_Label("BLOCK"))).upper()
|
154 |
|
|
v = _NotSupportedVisitor(ast)
|
155 |
|
|
compiler.walk(ast, v)
|
156 |
|
|
if isinstance(g, _AlwaysComb):
|
157 |
|
|
v = _AnalyzeAlwaysCombVisitor(ast, g.senslist)
|
158 |
|
|
else:
|
159 |
|
|
v = _AnalyzeAlwaysDecoVisitor(ast, g.senslist)
|
160 |
|
|
compiler.walk(ast, v)
|
161 |
|
|
else: # @instance
|
162 |
|
|
f = g.gen.gi_frame
|
163 |
|
|
s = inspect.getsource(f)
|
164 |
|
|
# remove decorators
|
165 |
|
|
s = re.sub(r"@.*", "", s)
|
166 |
|
|
s = s.lstrip()
|
167 |
|
|
ast = compiler.parse(s)
|
168 |
|
|
# print ast
|
169 |
|
|
ast.sourcefile = inspect.getsourcefile(f)
|
170 |
|
|
ast.lineoffset = inspect.getsourcelines(f)[1]-1
|
171 |
|
|
ast.symdict = f.f_globals.copy()
|
172 |
|
|
ast.symdict.update(f.f_locals)
|
173 |
|
|
ast.callstack = []
|
174 |
|
|
ast.name = absnames.get(id(g), str(_Label("BLOCK"))).upper()
|
175 |
|
|
v = _NotSupportedVisitor(ast)
|
176 |
|
|
compiler.walk(ast, v)
|
177 |
|
|
v = _AnalyzeBlockVisitor(ast)
|
178 |
|
|
compiler.walk(ast, v)
|
179 |
|
|
genlist.append(ast)
|
180 |
|
|
return genlist
|
181 |
|
|
|
182 |
|
|
|
183 |
|
|
class _NotSupportedVisitor(_ConversionMixin):
|
184 |
|
|
|
185 |
|
|
def __init__(self, ast):
|
186 |
|
|
self.ast = ast
|
187 |
|
|
self.toplevel = True
|
188 |
|
|
|
189 |
|
|
def visitAssList(self, node, *args):
|
190 |
|
|
self.raiseError(node, _error.NotSupported, "list assignment")
|
191 |
|
|
def visitAssTuple(self, node, *args):
|
192 |
|
|
self.raiseError(node, _error.NotSupported, "tuple assignment")
|
193 |
|
|
def visitBackquote(self, node, *args):
|
194 |
|
|
self.raiseError(node, _error.NotSupported, "backquote")
|
195 |
|
|
def visitClass(self, node, *args):
|
196 |
|
|
self.raiseError(node, _error.NotSupported, "class statement")
|
197 |
|
|
def visitDict(self, node, *args):
|
198 |
|
|
self.raiseError(node, _error.NotSupported, "dictionary")
|
199 |
|
|
def visitDiv(self, node, *args):
|
200 |
|
|
self.raiseError(node, _error.NotSupported, "true division - consider '//'")
|
201 |
|
|
def visitEllipsis(self, node, *args):
|
202 |
|
|
self.raiseError(node, _error.NotSupported, "ellipsis")
|
203 |
|
|
def visitExec(self, node, *args):
|
204 |
|
|
self.raiseError(node, _error.NotSupported, "exec statement")
|
205 |
|
|
def visitExpression(self, node, *args):
|
206 |
|
|
self.raiseError(node, _error.NotSupported, "Expression node")
|
207 |
|
|
def visitFrom(self, node, *args):
|
208 |
|
|
self.raiseError(node, _error.NotSupported, "from statement")
|
209 |
|
|
def visitGlobal(self, node, *args):
|
210 |
|
|
self.raiseError(node, _error.NotSupported, "global statement")
|
211 |
|
|
def visitImport(self, node, *args):
|
212 |
|
|
self.raiseError(node, _error.NotSupported, "import statement")
|
213 |
|
|
def visitLambda(self, node, *args):
|
214 |
|
|
self.raiseError(node, _error.NotSupported, "lambda statement")
|
215 |
|
|
def visitListComp(self, node, *args):
|
216 |
|
|
if len(node.quals) > 1:
|
217 |
|
|
self.raiseError(node, _error.NotSupported, "multiple for statements in list comprehension")
|
218 |
|
|
self.visitChildNodes(node)
|
219 |
|
|
def visitListCompIf(self, node, *args):
|
220 |
|
|
self.raiseError(node, _error.NotSupported, "if statement in list comprehension")
|
221 |
|
|
def visitList(self, node, *args):
|
222 |
|
|
self.raiseError(node, _error.NotSupported, "list")
|
223 |
|
|
def visitSliceObj(self, node):
|
224 |
|
|
self.raiseError(node, _error.NotSupported, "slice object")
|
225 |
|
|
def visitTryExcept(self, node, *args):
|
226 |
|
|
self.raiseError(node, _error.NotSupported, "try-except statement")
|
227 |
|
|
def visitTryFinally(self, node, *args):
|
228 |
|
|
self.raiseError(node, _error.NotSupported, "try-finally statement")
|
229 |
|
|
|
230 |
|
|
def visitAnd(self, node):
|
231 |
|
|
self.visitChildNodes(node)
|
232 |
|
|
|
233 |
|
|
def visitOr(self, node):
|
234 |
|
|
self.visitChildNodes(node)
|
235 |
|
|
|
236 |
|
|
def visitAssign(self, node, *args):
|
237 |
|
|
if len(node.nodes) > 1:
|
238 |
|
|
self.raiseError(node, _error.NotSupported, "multiple assignments")
|
239 |
|
|
self.visit(node.nodes[0], *args)
|
240 |
|
|
self.visit(node.expr, *args)
|
241 |
|
|
|
242 |
|
|
def visitCallFunc(self, node):
|
243 |
|
|
if node.star_args:
|
244 |
|
|
self.raiseError(node, _error.NotSupported, "extra positional arguments")
|
245 |
|
|
if node.dstar_args:
|
246 |
|
|
self.raiseError(node, _error.NotSupported, "extra named arguments")
|
247 |
|
|
# f = eval(_unparse(node.node), self.ast.symdict)
|
248 |
|
|
self.visitChildNodes(node)
|
249 |
|
|
|
250 |
|
|
def visitCompare(self, node, *args):
|
251 |
|
|
if len(node.ops) != 1:
|
252 |
|
|
self.raiseError(node, _error.NotSupported, "chained comparison")
|
253 |
|
|
self.visitChildNodes(node, *args)
|
254 |
|
|
|
255 |
|
|
def visitFunction(self, node, *args):
|
256 |
|
|
if node.flags != 0: # check flags
|
257 |
|
|
self.raiseError(node, _error.NotSupported, "extra positional or named arguments")
|
258 |
|
|
if not self.toplevel:
|
259 |
|
|
self.raiseError(node, _error.NotSupported, "embedded function definition")
|
260 |
|
|
self.toplevel = False
|
261 |
|
|
self.visitChildNodes(node, *args)
|
262 |
|
|
|
263 |
|
|
def visitIf(self, node, *args):
|
264 |
|
|
node.ignore = False
|
265 |
|
|
if len(node.tests) == 1 and not node.else_:
|
266 |
|
|
test = node.tests[0][0]
|
267 |
|
|
if isinstance(test, compiler.ast.Name):
|
268 |
|
|
if test.name == '__debug__':
|
269 |
|
|
node.ignore = True
|
270 |
|
|
return # skip
|
271 |
|
|
for test, suite in node.tests:
|
272 |
|
|
self.visit(test)
|
273 |
|
|
self.visit(suite)
|
274 |
|
|
if node.else_:
|
275 |
|
|
self.visit(node.else_)
|
276 |
|
|
|
277 |
|
|
def visitPrintnl(self, node, *args):
|
278 |
|
|
if node.dest is not None:
|
279 |
|
|
self.raiseError(node, _error.NotSupported, "printing to a file with >> syntax")
|
280 |
|
|
self.visitChildNodes(node, *args)
|
281 |
|
|
|
282 |
|
|
def visitPrint(self, node, *args):
|
283 |
|
|
self.raiseError(node, _error.NotSupported, "printing without newline")
|
284 |
|
|
|
285 |
|
|
# visitPrint = visitPrintnl
|
286 |
|
|
|
287 |
|
|
|
288 |
|
|
|
289 |
|
|
def getNrBits(obj):
|
290 |
|
|
if hasattr(obj, '_nrbits'):
|
291 |
|
|
return obj._nrbits
|
292 |
|
|
return None
|
293 |
|
|
|
294 |
|
|
def hasType(obj, theType):
|
295 |
|
|
if isinstance(obj, theType):
|
296 |
|
|
return True
|
297 |
|
|
if isinstance(obj, Signal):
|
298 |
|
|
if isinstance(obj._val, theType):
|
299 |
|
|
return True
|
300 |
|
|
return False
|
301 |
|
|
|
302 |
|
|
|
303 |
|
|
class ReferenceStack(list):
|
304 |
|
|
def push(self):
|
305 |
|
|
self.append(Set())
|
306 |
|
|
def add(self, item):
|
307 |
|
|
self[-1].add(item)
|
308 |
|
|
def __contains__(self, item):
|
309 |
|
|
for s in self:
|
310 |
|
|
if item in s:
|
311 |
|
|
return True
|
312 |
|
|
return False
|
313 |
|
|
|
314 |
|
|
# auxiliary types to aid type checking
|
315 |
|
|
## class _EdgeDetector(object):
|
316 |
|
|
## pass
|
317 |
|
|
|
318 |
|
|
class _Ram(object):
|
319 |
|
|
__slots__ = ['elObj', 'depth']
|
320 |
|
|
|
321 |
|
|
|
322 |
|
|
class _Rom(object):
|
323 |
|
|
__slots__ = ['rom']
|
324 |
|
|
def __init__(self, rom):
|
325 |
|
|
self.rom = rom
|
326 |
|
|
|
327 |
|
|
|
328 |
|
|
def _maybeNegative(obj):
|
329 |
|
|
if hasattr(obj, '_min') and (obj._min is not None) and (obj._min < 0):
|
330 |
|
|
return True
|
331 |
|
|
if isinstance(obj, (int, long)) and obj < 0:
|
332 |
|
|
return True
|
333 |
|
|
return False
|
334 |
|
|
|
335 |
|
|
re_str = re.compile(r"[^%]+")
|
336 |
|
|
re_ConvSpec = re.compile(r"%(?P[-]?)(?P[0-9]*)(?P[sd])")
|
337 |
|
|
|
338 |
|
|
class ConvSpec(object):
|
339 |
|
|
def __init__(self, **kwargs):
|
340 |
|
|
self.justified = "RIGHT"
|
341 |
|
|
self.width = 0
|
342 |
|
|
self.conv = str
|
343 |
|
|
if kwargs['justified'] == '-':
|
344 |
|
|
self.justified = "LEFT"
|
345 |
|
|
if kwargs['width']:
|
346 |
|
|
self.width = int(kwargs['width'])
|
347 |
|
|
if kwargs['conv'] == 'd':
|
348 |
|
|
self.conv = int
|
349 |
|
|
|
350 |
|
|
defaultConvSpec = ConvSpec(**re_ConvSpec.match(r"%s").groupdict())
|
351 |
|
|
|
352 |
|
|
|
353 |
|
|
class _AnalyzeVisitor(_ConversionMixin):
|
354 |
|
|
|
355 |
|
|
def __init__(self, ast):
|
356 |
|
|
ast.sigdict = {}
|
357 |
|
|
ast.vardict = {}
|
358 |
|
|
ast.inputs = Set()
|
359 |
|
|
ast.outputs = Set()
|
360 |
|
|
ast.argnames = []
|
361 |
|
|
ast.kind = None
|
362 |
|
|
ast.hasYield = 0
|
363 |
|
|
ast.hasRom = False
|
364 |
|
|
ast.hasPrint = False
|
365 |
|
|
self.ast = ast
|
366 |
|
|
self.labelStack = []
|
367 |
|
|
self.refStack = ReferenceStack()
|
368 |
|
|
self.globalRefs = Set()
|
369 |
|
|
|
370 |
|
|
|
371 |
|
|
def binaryOp(self, node, *args):
|
372 |
|
|
self.visit(node.left)
|
373 |
|
|
self.visit(node.right)
|
374 |
|
|
node.obj = int(-1)
|
375 |
|
|
node.signed = node.left.signed or node.right.signed
|
376 |
|
|
visitAdd = binaryOp
|
377 |
|
|
visitFloorDiv = binaryOp
|
378 |
|
|
visitLeftShift = binaryOp
|
379 |
|
|
visitMul = binaryOp
|
380 |
|
|
visitPower = binaryOp
|
381 |
|
|
visitMod = binaryOp
|
382 |
|
|
visitRightShift = binaryOp
|
383 |
|
|
visitSub = binaryOp
|
384 |
|
|
|
385 |
|
|
def multiBitOp(self, node, *args):
|
386 |
|
|
node.signed = False
|
387 |
|
|
for n in node.nodes:
|
388 |
|
|
self.visit(n)
|
389 |
|
|
if n.signed:
|
390 |
|
|
node.signed = True
|
391 |
|
|
node.obj = None
|
392 |
|
|
for n in node.nodes:
|
393 |
|
|
if node.obj is None:
|
394 |
|
|
node.obj = n.obj
|
395 |
|
|
elif isinstance(node.obj, type(n.obj)):
|
396 |
|
|
node.obj = n.obj
|
397 |
|
|
def visitBitand(self, node, *args):
|
398 |
|
|
self.multiBitOp(node, *args)
|
399 |
|
|
def visitBitor(self, node, *args):
|
400 |
|
|
self.multiBitOp(node, *args)
|
401 |
|
|
def visitBitxor(self, node, *args):
|
402 |
|
|
self.multiBitOp(node, *args)
|
403 |
|
|
def multiLogicalOp(self, node, *args):
|
404 |
|
|
for n in node.nodes:
|
405 |
|
|
self.visit(n, *args)
|
406 |
|
|
for n in node.nodes:
|
407 |
|
|
if not hasType(n.obj, bool):
|
408 |
|
|
self.raiseError(node, _error.NotSupported, "non-boolean argument in logical operator")
|
409 |
|
|
node.obj = bool()
|
410 |
|
|
def visitAnd(self, node, *args):
|
411 |
|
|
self.multiLogicalOp(node, *args)
|
412 |
|
|
def visitOr(self, node, *args):
|
413 |
|
|
self.multiLogicalOp(node, *args)
|
414 |
|
|
|
415 |
|
|
# unaryOp's
|
416 |
|
|
def visitInvert(self, node, *args):
|
417 |
|
|
self.visit(node.expr)
|
418 |
|
|
node.obj = node.expr.obj
|
419 |
|
|
node.signed = node.expr.signed
|
420 |
|
|
def visitNot(self, node, *args):
|
421 |
|
|
self.visit(node.expr)
|
422 |
|
|
node.obj = bool()
|
423 |
|
|
print(node.expr)
|
424 |
|
|
node.signed = node.expr.signed
|
425 |
|
|
def visitUnaryAdd(self, node, *args):
|
426 |
|
|
self.visit(node.expr)
|
427 |
|
|
node.obj = int(-1)
|
428 |
|
|
node.signed = node.expr.signed
|
429 |
|
|
def visitUnarySub(self, node, *args):
|
430 |
|
|
self.visit(node.expr)
|
431 |
|
|
node.obj = int(-1)
|
432 |
|
|
node.signed = node.expr.signed
|
433 |
|
|
if isinstance(node.expr, astNode.Const):
|
434 |
|
|
node.signed = True
|
435 |
|
|
|
436 |
|
|
def visitAssAttr(self, node, access=_access.OUTPUT, *args):
|
437 |
|
|
if node.attrname != 'next':
|
438 |
|
|
self.raiseError(node, _error.NotSupported, "attribute assignment")
|
439 |
|
|
self.ast.kind = _kind.TASK
|
440 |
|
|
self.visit(node.expr, _access.OUTPUT)
|
441 |
|
|
|
442 |
|
|
def visitAssign(self, node, access=_access.OUTPUT, *args):
|
443 |
|
|
target, expr = node.nodes[0], node.expr
|
444 |
|
|
self.visit(target, _access.OUTPUT)
|
445 |
|
|
if isinstance(target, astNode.AssName):
|
446 |
|
|
self.visit(expr, _access.INPUT, _kind.DECLARATION)
|
447 |
|
|
node.kind = _kind.DECLARATION
|
448 |
|
|
n = target.name
|
449 |
|
|
if n in self.ast.sigdict:
|
450 |
|
|
self.raiseError(node, _error.ShadowingVar)
|
451 |
|
|
obj = self.getObj(expr)
|
452 |
|
|
if obj is None:
|
453 |
|
|
self.raiseError(node, _error.TypeInfer, n)
|
454 |
|
|
if isinstance(obj, intbv):
|
455 |
|
|
if len(obj) == 0:
|
456 |
|
|
self.raiseError(node, _error.IntbvBitWidth, n)
|
457 |
|
|
## if obj._min < 0:
|
458 |
|
|
## self.raiseError(node, _error.IntbvSign, n)
|
459 |
|
|
if obj._min < 0:
|
460 |
|
|
_signed = True
|
461 |
|
|
if n in self.ast.vardict:
|
462 |
|
|
curObj = self.ast.vardict[n]
|
463 |
|
|
if isinstance(obj, type(curObj)):
|
464 |
|
|
pass
|
465 |
|
|
elif isinstance(curObj, type(obj)):
|
466 |
|
|
self.ast.vardict[n] = obj
|
467 |
|
|
else:
|
468 |
|
|
self.raiseError(node, _error.TypeMismatch, n)
|
469 |
|
|
if getNrBits(obj) != getNrBits(curObj):
|
470 |
|
|
self.raiseError(node, _error.NrBitsMismatch, n)
|
471 |
|
|
else:
|
472 |
|
|
self.ast.vardict[n] = obj
|
473 |
|
|
else:
|
474 |
|
|
self.visit(expr, _access.INPUT)
|
475 |
|
|
|
476 |
|
|
def visitAssName(self, node, *args):
|
477 |
|
|
n = node.name
|
478 |
|
|
if n in ("__verilog__", "__vhdl__"):
|
479 |
|
|
self.raiseError(node, _error.NotSupported,
|
480 |
|
|
"%s in generator function" % n)
|
481 |
|
|
# XXX ?
|
482 |
|
|
if n in self.globalRefs:
|
483 |
|
|
self.raiseError(node, _error.UnboundLocal, n)
|
484 |
|
|
self.refStack.add(n)
|
485 |
|
|
|
486 |
|
|
def visitAugAssign(self, node, access=_access.INPUT, *args):
|
487 |
|
|
self.visit(node.node, _access.INOUT)
|
488 |
|
|
self.visit(node.expr, _access.INPUT)
|
489 |
|
|
|
490 |
|
|
def visitBreak(self, node, *args):
|
491 |
|
|
self.labelStack[-2].isActive = True
|
492 |
|
|
|
493 |
|
|
def visitCallFunc(self, node, *args):
|
494 |
|
|
self.visit(node.node)
|
495 |
|
|
for arg in node.args:
|
496 |
|
|
self.visit(arg, _access.UNKNOWN)
|
497 |
|
|
argsAreInputs = True
|
498 |
|
|
f = self.getObj(node.node)
|
499 |
|
|
node.obj = None
|
500 |
|
|
node.signed = False
|
501 |
|
|
if type(f) is type and issubclass(f, intbv):
|
502 |
|
|
node.obj = self.getVal(node)
|
503 |
|
|
elif f is concat:
|
504 |
|
|
node.obj = self.getVal(node)
|
505 |
|
|
elif f is len:
|
506 |
|
|
node.obj = int(0) # XXX
|
507 |
|
|
elif f is bool:
|
508 |
|
|
node.obj = bool()
|
509 |
|
|
elif f in (int, long, ord):
|
510 |
|
|
node.obj = int(-1)
|
511 |
|
|
## elif f in (posedge , negedge):
|
512 |
|
|
## node.obj = _EdgeDetector()
|
513 |
|
|
elif f is delay:
|
514 |
|
|
node.obj = delay(0)
|
515 |
|
|
### suprize: identity comparison on unbound methods doesn't work in python 2.5??
|
516 |
|
|
elif f == intbv.signed:
|
517 |
|
|
node.obj = int(-1)
|
518 |
|
|
node.signed = True
|
519 |
|
|
elif f in myhdlObjects:
|
520 |
|
|
pass
|
521 |
|
|
elif f in builtinObjects:
|
522 |
|
|
pass
|
523 |
|
|
elif type(f) is FunctionType:
|
524 |
|
|
argsAreInputs = False
|
525 |
|
|
s = inspect.getsource(f)
|
526 |
|
|
s = s.lstrip()
|
527 |
|
|
ast = compiler.parse(s)
|
528 |
|
|
# print ast
|
529 |
|
|
fname = f.__name__
|
530 |
|
|
ast.name = _Label(fname)
|
531 |
|
|
ast.sourcefile = inspect.getsourcefile(f)
|
532 |
|
|
ast.lineoffset = inspect.getsourcelines(f)[1]-1
|
533 |
|
|
ast.symdict = f.func_globals.copy()
|
534 |
|
|
if fname in self.ast.callstack:
|
535 |
|
|
self.raiseError(node, _error.NotSupported, "Recursive call")
|
536 |
|
|
ast.callstack = self.ast.callstack[:]
|
537 |
|
|
ast.callstack.append(fname)
|
538 |
|
|
# handle free variables
|
539 |
|
|
if f.func_code.co_freevars:
|
540 |
|
|
for n, c in zip(f.func_code.co_freevars, f.func_closure):
|
541 |
|
|
obj = _cell_deref(c)
|
542 |
|
|
if not isinstance(obj, (int, long, Signal)):
|
543 |
|
|
self.raiseError(node, _error.FreeVarTypeError, n)
|
544 |
|
|
ast.symdict[n] = obj
|
545 |
|
|
v = _NotSupportedVisitor(ast)
|
546 |
|
|
compiler.walk(ast, v)
|
547 |
|
|
v = _AnalyzeFuncVisitor(ast, node.args)
|
548 |
|
|
compiler.walk(ast, v)
|
549 |
|
|
node.obj = ast.returnObj
|
550 |
|
|
node.ast = ast
|
551 |
|
|
for i, arg in enumerate(node.args):
|
552 |
|
|
if isinstance(arg, astNode.Keyword):
|
553 |
|
|
n = arg.name
|
554 |
|
|
else: # Name
|
555 |
|
|
n = ast.argnames[i]
|
556 |
|
|
if n in ast.outputs:
|
557 |
|
|
self.visit(arg, _access.OUTPUT)
|
558 |
|
|
if n in ast.inputs:
|
559 |
|
|
self.visit(arg, _access.INPUT)
|
560 |
|
|
elif type(f) is MethodType:
|
561 |
|
|
self.raiseError(node,_error.NotSupported, "method call: '%s'" % f.__name__)
|
562 |
|
|
else:
|
563 |
|
|
raise AssertionError("Unexpected callable")
|
564 |
|
|
if argsAreInputs:
|
565 |
|
|
for arg in node.args:
|
566 |
|
|
self.visit(arg, _access.INPUT)
|
567 |
|
|
|
568 |
|
|
def visitCompare(self, node, *args):
|
569 |
|
|
node.obj = bool()
|
570 |
|
|
node.signed = False
|
571 |
|
|
for n in node.getChildNodes():
|
572 |
|
|
self.visit(n, *args)
|
573 |
|
|
if n.signed:
|
574 |
|
|
node.signed = True
|
575 |
|
|
op, arg = node.ops[0]
|
576 |
|
|
## node.expr.target = self.getObj(arg)
|
577 |
|
|
## arg.target = self.getObj(node.expr)
|
578 |
|
|
# detect specialized case for the test
|
579 |
|
|
if op == '==' and isinstance(node.expr, astNode.Name):
|
580 |
|
|
n = node.expr.name
|
581 |
|
|
# check wether it can be a case
|
582 |
|
|
if isinstance(arg.obj, EnumItemType):
|
583 |
|
|
node.case = (node.expr, arg.obj)
|
584 |
|
|
# check whether it can be part of an edge check
|
585 |
|
|
elif n in self.ast.sigdict:
|
586 |
|
|
sig = self.ast.sigdict[n]
|
587 |
|
|
v = self.getValue(arg)
|
588 |
|
|
if v is not None:
|
589 |
|
|
if v == 0:
|
590 |
|
|
node.edge = sig.negedge
|
591 |
|
|
elif v == 1:
|
592 |
|
|
node.edge = sig.posedge
|
593 |
|
|
|
594 |
|
|
|
595 |
|
|
def visitConst(self, node, *args):
|
596 |
|
|
node.signed = False
|
597 |
|
|
if node.value in (0, 1):
|
598 |
|
|
node.obj = bool(node.value)
|
599 |
|
|
elif isinstance(node.value, (int, str)):
|
600 |
|
|
node.obj = node.value
|
601 |
|
|
else:
|
602 |
|
|
node.obj = None
|
603 |
|
|
|
604 |
|
|
def visitContinue(self, node, *args):
|
605 |
|
|
self.labelStack[-1].isActive = True
|
606 |
|
|
|
607 |
|
|
def visitFor(self, node, *args):
|
608 |
|
|
node.breakLabel = _Label("BREAK")
|
609 |
|
|
node.loopLabel = _Label("LOOP")
|
610 |
|
|
self.labelStack.append(node.breakLabel)
|
611 |
|
|
self.labelStack.append(node.loopLabel)
|
612 |
|
|
self.refStack.push()
|
613 |
|
|
self.visit(node.assign)
|
614 |
|
|
var = node.assign.name
|
615 |
|
|
self.ast.vardict[var] = int(-1)
|
616 |
|
|
|
617 |
|
|
cf = node.list
|
618 |
|
|
self.visit(cf)
|
619 |
|
|
self.require(node, isinstance(cf, astNode.CallFunc), "Expected (down)range call")
|
620 |
|
|
f = self.getObj(cf.node)
|
621 |
|
|
self.require(node, f in (range, downrange), "Expected (down)range call")
|
622 |
|
|
|
623 |
|
|
self.visit(node.body, *args)
|
624 |
|
|
self.refStack.pop()
|
625 |
|
|
self.require(node, node.else_ is None, "for-else not supported")
|
626 |
|
|
self.labelStack.pop()
|
627 |
|
|
self.labelStack.pop()
|
628 |
|
|
|
629 |
|
|
def visitFunction(self, node, *args):
|
630 |
|
|
raise AssertionError("subclass must implement this")
|
631 |
|
|
|
632 |
|
|
def visitGetattr(self, node, *args):
|
633 |
|
|
self.visit(node.expr, *args)
|
634 |
|
|
node.obj = None
|
635 |
|
|
node.signed = False
|
636 |
|
|
if isinstance(node.expr, astNode.Name):
|
637 |
|
|
n = node.expr.name
|
638 |
|
|
if (n not in self.ast.vardict) and (n not in self.ast.symdict):
|
639 |
|
|
raise AssertionError("attribute target: %s" % n)
|
640 |
|
|
obj = node.expr.obj
|
641 |
|
|
if isinstance(obj, Signal):
|
642 |
|
|
if node.attrname == 'posedge':
|
643 |
|
|
node.obj = obj.posedge
|
644 |
|
|
elif node.attrname == 'negedge':
|
645 |
|
|
node.obj = obj.negedge
|
646 |
|
|
elif node.attrname in ('val', 'next'):
|
647 |
|
|
node.obj = obj.val
|
648 |
|
|
if isinstance(obj, (intbv, Signal)):
|
649 |
|
|
if node.attrname == 'min':
|
650 |
|
|
node.obj = obj.min
|
651 |
|
|
elif node.attrname == 'max':
|
652 |
|
|
node.obj = obj.max
|
653 |
|
|
elif node.attrname == 'signed':
|
654 |
|
|
node.obj = intbv.signed
|
655 |
|
|
if isinstance(obj, EnumType):
|
656 |
|
|
print("Object:" + `obj`)
|
657 |
|
|
print("Name:" + `node.attrname`)
|
658 |
|
|
assert hasattr(obj, node.attrname)
|
659 |
|
|
node.obj = getattr(obj, node.attrname)
|
660 |
|
|
if obj not in _enumTypeSet:
|
661 |
|
|
_enumTypeSet.add(obj)
|
662 |
|
|
suf = _genUniqueSuffix.next()
|
663 |
|
|
obj._setName(n+suf)
|
664 |
|
|
if node.obj is None: # attribute lookup failed
|
665 |
|
|
self.raiseError(node, _error.UnsupportedAttribute, node.attrname)
|
666 |
|
|
|
667 |
|
|
|
668 |
|
|
|
669 |
|
|
def visitIf(self, node, *args):
|
670 |
|
|
if node.ignore:
|
671 |
|
|
return
|
672 |
|
|
for test, suite in node.tests:
|
673 |
|
|
self.visit(test, *args)
|
674 |
|
|
self.refStack.push()
|
675 |
|
|
self.visit(suite, *args)
|
676 |
|
|
self.refStack.pop()
|
677 |
|
|
if node.else_:
|
678 |
|
|
self.refStack.push()
|
679 |
|
|
self.visit(node.else_, *args)
|
680 |
|
|
self.refStack.pop()
|
681 |
|
|
# check whether the if can be mapped to a (parallel) case
|
682 |
|
|
node.isCase = node.isFullCase = False
|
683 |
|
|
test1 = node.tests[0][0]
|
684 |
|
|
if not hasattr(test1, 'case'):
|
685 |
|
|
return
|
686 |
|
|
var1, item1 = test1.case
|
687 |
|
|
# don't infer a case if there's no elsif test
|
688 |
|
|
if not node.tests[1:]:
|
689 |
|
|
return
|
690 |
|
|
choices = Set()
|
691 |
|
|
choices.add(item1._index)
|
692 |
|
|
for test, suite in node.tests[1:]:
|
693 |
|
|
if not hasattr(test, 'case'):
|
694 |
|
|
return
|
695 |
|
|
var, item = test.case
|
696 |
|
|
if var.name != var1.name or type(item) is not type(item1):
|
697 |
|
|
return
|
698 |
|
|
if item._index in choices:
|
699 |
|
|
return
|
700 |
|
|
choices.add(item._index)
|
701 |
|
|
node.isCase = True
|
702 |
|
|
node.caseVar = var1
|
703 |
|
|
if (len(choices) == item1._nritems) or (node.else_ is not None):
|
704 |
|
|
node.isFullCase = True
|
705 |
|
|
|
706 |
|
|
def visitListComp(self, node, *args):
|
707 |
|
|
mem = node.obj = _Ram()
|
708 |
|
|
self.visit(node.expr, _access.INPUT, _kind.DECLARATION)
|
709 |
|
|
mem.elObj = self.getObj(node.expr)
|
710 |
|
|
if not isinstance(mem.elObj, intbv) or not len(mem.elObj) > 0:
|
711 |
|
|
self.raiseError(node, _error.UnsupportedListComp)
|
712 |
|
|
cf = node.quals[0].list
|
713 |
|
|
self.visit(cf)
|
714 |
|
|
if not isinstance(cf, astNode.CallFunc):
|
715 |
|
|
self.raiseError(node, _error.UnsupportedListComp)
|
716 |
|
|
f = self.getObj(cf.node)
|
717 |
|
|
if f is not range or len(cf.args) != 1:
|
718 |
|
|
self.raiseError(node, _error.UnsupportedListComp)
|
719 |
|
|
mem.depth = cf.args[0].obj
|
720 |
|
|
|
721 |
|
|
def visitName(self, node, access=_access.INPUT, *args):
|
722 |
|
|
n = node.name
|
723 |
|
|
node.obj = None
|
724 |
|
|
if n not in self.refStack:
|
725 |
|
|
if n in self.ast.vardict:
|
726 |
|
|
self.raiseError(node, _error.UnboundLocal, n)
|
727 |
|
|
self.globalRefs.add(n)
|
728 |
|
|
if n in self.ast.sigdict:
|
729 |
|
|
node.obj = sig = self.ast.sigdict[n]
|
730 |
|
|
if not isinstance(sig, Signal):
|
731 |
|
|
# print "not a signal: %s" % n
|
732 |
|
|
pass
|
733 |
|
|
else:
|
734 |
|
|
if sig._type is bool:
|
735 |
|
|
node.edge = sig.posedge
|
736 |
|
|
if access == _access.INPUT:
|
737 |
|
|
self.ast.inputs.add(n)
|
738 |
|
|
elif access == _access.OUTPUT:
|
739 |
|
|
self.ast.kind = _kind.TASK
|
740 |
|
|
if n in self.ast.outputs:
|
741 |
|
|
node.kind = _kind.REG
|
742 |
|
|
self.ast.outputs.add(n)
|
743 |
|
|
elif access == _access.UNKNOWN:
|
744 |
|
|
pass
|
745 |
|
|
else:
|
746 |
|
|
raise AssertionError
|
747 |
|
|
if n in self.ast.vardict:
|
748 |
|
|
obj = self.ast.vardict[n]
|
749 |
|
|
if access == _access.INOUT:
|
750 |
|
|
# upgrade bool to int for augmented assignments
|
751 |
|
|
if isinstance(obj, bool):
|
752 |
|
|
obj = int(0)
|
753 |
|
|
self.ast.vardict[n] = obj
|
754 |
|
|
node.obj = obj
|
755 |
|
|
elif n in self.ast.symdict:
|
756 |
|
|
node.obj = self.ast.symdict[n]
|
757 |
|
|
if _isTupleOfInts(node.obj):
|
758 |
|
|
node.obj = _Rom(node.obj)
|
759 |
|
|
self.ast.hasRom = True
|
760 |
|
|
elif isinstance(node.obj, int):
|
761 |
|
|
node.value = node.obj
|
762 |
|
|
elif n in __builtin__.__dict__:
|
763 |
|
|
node.obj = __builtin__.__dict__[n]
|
764 |
|
|
else:
|
765 |
|
|
pass
|
766 |
|
|
node.signed = _maybeNegative(node.obj)
|
767 |
|
|
## node.target = node.obj
|
768 |
|
|
|
769 |
|
|
def visitReturn(self, node, *args):
|
770 |
|
|
self.raiseError(node, _error.NotSupported, "return statement")
|
771 |
|
|
|
772 |
|
|
def visitPrintnl(self, node, *args):
|
773 |
|
|
self.ast.hasPrint = True
|
774 |
|
|
f = []
|
775 |
|
|
nr = 0
|
776 |
|
|
a = []
|
777 |
|
|
for n in node.nodes:
|
778 |
|
|
if isinstance(n, astNode.Mod) and \
|
779 |
|
|
(isinstance(n.left, astNode.Const) and isinstance(n.left.value, str)):
|
780 |
|
|
if isinstance(n.right, astNode.Tuple):
|
781 |
|
|
a.extend(n.right.nodes)
|
782 |
|
|
else:
|
783 |
|
|
a.append(n.right)
|
784 |
|
|
s = n.left.value
|
785 |
|
|
while s:
|
786 |
|
|
if not s:
|
787 |
|
|
break
|
788 |
|
|
if s[:2] == "%%":
|
789 |
|
|
f.append("%")
|
790 |
|
|
s = s[2:]
|
791 |
|
|
continue
|
792 |
|
|
m = re_ConvSpec.match(s)
|
793 |
|
|
if m:
|
794 |
|
|
c = ConvSpec(**m.groupdict())
|
795 |
|
|
if c.justified != "RIGHT":
|
796 |
|
|
self.raiseError(node,_error.UnsupportedFormatString,
|
797 |
|
|
"format justification specification: %s" %s)
|
798 |
|
|
if c.width != 0:
|
799 |
|
|
self.raiseError(node,_error.UnsupportedFormatString,
|
800 |
|
|
"format width specification: %s" %s)
|
801 |
|
|
f.append(c)
|
802 |
|
|
s = s[m.end():]
|
803 |
|
|
nr += 1
|
804 |
|
|
continue
|
805 |
|
|
m = re_str.match(s)
|
806 |
|
|
if m:
|
807 |
|
|
f.append(s[:m.end()])
|
808 |
|
|
s = s[m.end():]
|
809 |
|
|
continue
|
810 |
|
|
self.raiseError(node, _error.UnsupportedFormatString, "%s" % s)
|
811 |
|
|
else:
|
812 |
|
|
f.append(defaultConvSpec)
|
813 |
|
|
a.append(n)
|
814 |
|
|
nr += 1
|
815 |
|
|
f.append(" ")
|
816 |
|
|
# remove last single space if it exists
|
817 |
|
|
if f:
|
818 |
|
|
f.pop()
|
819 |
|
|
node.format = f
|
820 |
|
|
node.args = a
|
821 |
|
|
if len(node.args) < nr:
|
822 |
|
|
self.raiseError(node, _error.FormatString, "not enough arguments")
|
823 |
|
|
if len(node.args) > nr:
|
824 |
|
|
self.raiseError(node, _error.FormatString, "too many arguments")
|
825 |
|
|
self.visitChildNodes(node, *args)
|
826 |
|
|
|
827 |
|
|
visitPrint = visitPrintnl
|
828 |
|
|
|
829 |
|
|
def visitSlice(self, node, access=_access.INPUT, kind=_kind.NORMAL, *args):
|
830 |
|
|
node.signed = False
|
831 |
|
|
self.visit(node.expr, access)
|
832 |
|
|
node.obj = self.getObj(node.expr)
|
833 |
|
|
if node.lower:
|
834 |
|
|
self.visit(node.lower, _access.INPUT)
|
835 |
|
|
if node.upper:
|
836 |
|
|
self.visit(node.upper, _access.INPUT)
|
837 |
|
|
if isinstance(node.obj , intbv):
|
838 |
|
|
if kind == _kind.DECLARATION:
|
839 |
|
|
self.require(node.lower, "Expected leftmost index")
|
840 |
|
|
leftind = self.getVal(node.lower)
|
841 |
|
|
if node.upper:
|
842 |
|
|
rightind = self.getVal(node.upper)
|
843 |
|
|
else:
|
844 |
|
|
rightind = 0
|
845 |
|
|
node.obj = node.obj[leftind:rightind]
|
846 |
|
|
|
847 |
|
|
|
848 |
|
|
def visitSubscript(self, node, access=_access.INPUT, *args):
|
849 |
|
|
self.visit(node.expr, access)
|
850 |
|
|
assert len(node.subs) == 1
|
851 |
|
|
self.visit(node.subs[0], _access.INPUT)
|
852 |
|
|
if isinstance(node.expr.obj, _Ram):
|
853 |
|
|
if node.flags == 'OP_ASSIGN':
|
854 |
|
|
self.raiseError(node, _error.ListElementAssign)
|
855 |
|
|
else:
|
856 |
|
|
node.obj = node.expr.obj.elObj
|
857 |
|
|
elif _isMem(node.expr.obj):
|
858 |
|
|
node.obj = node.expr.obj[0]
|
859 |
|
|
elif isinstance(node.expr.obj, _Rom):
|
860 |
|
|
node.obj = int(-1)
|
861 |
|
|
elif isinstance(node.expr.obj, intbv):
|
862 |
|
|
node.obj = bool()
|
863 |
|
|
else:
|
864 |
|
|
node.obj = bool() # XXX default
|
865 |
|
|
node.signed = _maybeNegative(node.obj)
|
866 |
|
|
|
867 |
|
|
def visitTuple(self, node, *args):
|
868 |
|
|
node.signed = False
|
869 |
|
|
self.visitChildNodes(node, *args)
|
870 |
|
|
|
871 |
|
|
def visitWhile(self, node, *args):
|
872 |
|
|
node.breakLabel = _Label("BREAK")
|
873 |
|
|
node.loopLabel = _Label("LOOP")
|
874 |
|
|
self.labelStack.append(node.breakLabel)
|
875 |
|
|
self.labelStack.append(node.loopLabel)
|
876 |
|
|
self.visit(node.test, *args)
|
877 |
|
|
self.refStack.push()
|
878 |
|
|
self.visit(node.body, *args)
|
879 |
|
|
self.refStack.pop()
|
880 |
|
|
y = node.body.nodes[0]
|
881 |
|
|
if isinstance(y, astNode.Discard):
|
882 |
|
|
y = y.expr
|
883 |
|
|
if node.test.obj == True and \
|
884 |
|
|
isinstance(y, astNode.Yield) and \
|
885 |
|
|
not self.ast.hasYield > 1 and \
|
886 |
|
|
not isinstance(self.getObj(y.value), delay):
|
887 |
|
|
node.kind = _kind.ALWAYS
|
888 |
|
|
self.ast.senslist = y.senslist
|
889 |
|
|
self.require(node, node.else_ is None, "while-else not supported")
|
890 |
|
|
self.labelStack.pop()
|
891 |
|
|
self.labelStack.pop()
|
892 |
|
|
|
893 |
|
|
def visitYield(self, node, *args):
|
894 |
|
|
self.ast.hasYield += 1
|
895 |
|
|
n = node.value
|
896 |
|
|
self.visit(n)
|
897 |
|
|
senslist = []
|
898 |
|
|
if isinstance(n, astNode.Tuple):
|
899 |
|
|
for n in n.nodes:
|
900 |
|
|
if not isinstance(n.obj, (Signal, _WaiterList)):
|
901 |
|
|
self.raiseError(node, _error.UnsupportedYield)
|
902 |
|
|
senslist.append(n.obj)
|
903 |
|
|
elif isinstance(n.obj, (Signal, _WaiterList, delay)):
|
904 |
|
|
senslist = [n.obj]
|
905 |
|
|
elif _isMem(n.obj):
|
906 |
|
|
senslist = n.obj
|
907 |
|
|
else:
|
908 |
|
|
self.raiseError(node, _error.UnsupportedYield)
|
909 |
|
|
node.senslist = senslist
|
910 |
|
|
|
911 |
|
|
## def visitModule(self, node, *args):
|
912 |
|
|
## self.visit(node.node)
|
913 |
|
|
## for n in self.ast.inputs:
|
914 |
|
|
## s = self.ast.sigdict[n]
|
915 |
|
|
## s._read = True
|
916 |
|
|
|
917 |
|
|
|
918 |
|
|
|
919 |
|
|
class _AnalyzeBlockVisitor(_AnalyzeVisitor):
|
920 |
|
|
|
921 |
|
|
def __init__(self, ast):
|
922 |
|
|
_AnalyzeVisitor.__init__(self, ast)
|
923 |
|
|
for n, v in self.ast.symdict.items():
|
924 |
|
|
if isinstance(v, Signal):
|
925 |
|
|
self.ast.sigdict[n] = v
|
926 |
|
|
|
927 |
|
|
def visitFunction(self, node, *args):
|
928 |
|
|
self.refStack.push()
|
929 |
|
|
self.visit(node.code)
|
930 |
|
|
self.ast.kind = _kind.ALWAYS
|
931 |
|
|
for n in node.code.nodes[:-1]:
|
932 |
|
|
if not self.getKind(n) == _kind.DECLARATION:
|
933 |
|
|
self.ast.kind = _kind.INITIAL
|
934 |
|
|
break
|
935 |
|
|
if self.ast.kind == _kind.ALWAYS:
|
936 |
|
|
w = node.code.nodes[-1]
|
937 |
|
|
if not self.getKind(w) == _kind.ALWAYS:
|
938 |
|
|
self.ast.kind = _kind.INITIAL
|
939 |
|
|
self.refStack.pop()
|
940 |
|
|
|
941 |
|
|
def visitModule(self, node, *args):
|
942 |
|
|
self.visit(node.node)
|
943 |
|
|
for n in self.ast.outputs:
|
944 |
|
|
s = self.ast.sigdict[n]
|
945 |
|
|
if s._driven:
|
946 |
|
|
self.raiseError(node, _error.SigMultipleDriven, n)
|
947 |
|
|
s._driven = "reg"
|
948 |
|
|
for n in self.ast.inputs:
|
949 |
|
|
s = self.ast.sigdict[n]
|
950 |
|
|
s._read = True
|
951 |
|
|
|
952 |
|
|
def visitReturn(self, node, *args):
|
953 |
|
|
### value should be None
|
954 |
|
|
if isinstance(node.value, astNode.Const) and node.value.value is None:
|
955 |
|
|
obj = None
|
956 |
|
|
elif isinstance(node.value, astNode.Name) and node.value.name == 'None':
|
957 |
|
|
obj = None
|
958 |
|
|
else:
|
959 |
|
|
self.raiseError(node, _error.NotSupported, "return value other than None")
|
960 |
|
|
|
961 |
|
|
|
962 |
|
|
class _AnalyzeAlwaysCombVisitor(_AnalyzeBlockVisitor):
|
963 |
|
|
|
964 |
|
|
def __init__(self, ast, senslist):
|
965 |
|
|
_AnalyzeBlockVisitor.__init__(self, ast)
|
966 |
|
|
self.ast.senslist = senslist
|
967 |
|
|
|
968 |
|
|
def visitFunction(self, node, *args):
|
969 |
|
|
self.refStack.push()
|
970 |
|
|
self.visit(node.code)
|
971 |
|
|
self.ast.kind = _kind.SIMPLE_ALWAYS_COMB
|
972 |
|
|
for n in node.code.nodes:
|
973 |
|
|
if isinstance(n, astNode.Assign) and \
|
974 |
|
|
isinstance(n.nodes[0], astNode.AssAttr) and \
|
975 |
|
|
self.getKind(n.nodes[0].expr) != _kind.REG:
|
976 |
|
|
pass
|
977 |
|
|
else:
|
978 |
|
|
self.ast.kind = _kind.ALWAYS_COMB
|
979 |
|
|
return
|
980 |
|
|
# rom access is expanded into a case statement
|
981 |
|
|
if self.ast.hasRom:
|
982 |
|
|
self.ast.kind = _kind.ALWAYS_COMB
|
983 |
|
|
self.refStack.pop()
|
984 |
|
|
|
985 |
|
|
def visitModule(self, node, *args):
|
986 |
|
|
_AnalyzeBlockVisitor.visitModule(self, node, *args)
|
987 |
|
|
if self.ast.kind == _kind.SIMPLE_ALWAYS_COMB:
|
988 |
|
|
for n in self.ast.outputs:
|
989 |
|
|
s = self.ast.sigdict[n]
|
990 |
|
|
s._driven = "wire"
|
991 |
|
|
|
992 |
|
|
|
993 |
|
|
class _AnalyzeAlwaysDecoVisitor(_AnalyzeBlockVisitor):
|
994 |
|
|
|
995 |
|
|
def __init__(self, ast, senslist):
|
996 |
|
|
_AnalyzeBlockVisitor.__init__(self, ast)
|
997 |
|
|
self.ast.senslist = senslist
|
998 |
|
|
|
999 |
|
|
def visitFunction(self, node, *args):
|
1000 |
|
|
self.refStack.push()
|
1001 |
|
|
self.visit(node.code)
|
1002 |
|
|
self.ast.kind = _kind.ALWAYS_DECO
|
1003 |
|
|
self.refStack.pop()
|
1004 |
|
|
|
1005 |
|
|
|
1006 |
|
|
|
1007 |
|
|
class _AnalyzeFuncVisitor(_AnalyzeVisitor):
|
1008 |
|
|
|
1009 |
|
|
def __init__(self, ast, args):
|
1010 |
|
|
_AnalyzeVisitor.__init__(self, ast)
|
1011 |
|
|
self.args = args
|
1012 |
|
|
self.ast.hasReturn = False
|
1013 |
|
|
self.ast.returnObj = None
|
1014 |
|
|
|
1015 |
|
|
def visitFunction(self, node, *args):
|
1016 |
|
|
self.refStack.push()
|
1017 |
|
|
argnames = node.argnames
|
1018 |
|
|
for i, arg in enumerate(self.args):
|
1019 |
|
|
if isinstance(arg, astNode.Keyword):
|
1020 |
|
|
n = arg.name
|
1021 |
|
|
self.ast.symdict[n] = self.getObj(arg.expr)
|
1022 |
|
|
else: # Name
|
1023 |
|
|
n = argnames[i]
|
1024 |
|
|
self.ast.symdict[n] = self.getObj(arg)
|
1025 |
|
|
self.ast.argnames.append(n)
|
1026 |
|
|
for n, v in self.ast.symdict.items():
|
1027 |
|
|
if isinstance(v, (Signal, intbv)):
|
1028 |
|
|
self.ast.sigdict[n] = v
|
1029 |
|
|
self.visit(node.code)
|
1030 |
|
|
self.refStack.pop()
|
1031 |
|
|
if self.ast.hasYield:
|
1032 |
|
|
self.raiseError(node, _error.NotSupported,
|
1033 |
|
|
"call to a generator function")
|
1034 |
|
|
if self.ast.kind == _kind.TASK:
|
1035 |
|
|
if self.ast.returnObj is not None:
|
1036 |
|
|
self.raiseError(node, _error.NotSupported,
|
1037 |
|
|
"function with side effects and return value")
|
1038 |
|
|
else:
|
1039 |
|
|
if self.ast.returnObj is None:
|
1040 |
|
|
self.raiseError(node, _error.NotSupported,
|
1041 |
|
|
"pure function without return value")
|
1042 |
|
|
|
1043 |
|
|
|
1044 |
|
|
def visitReturn(self, node, *args):
|
1045 |
|
|
self.visit(node.value, _access.INPUT, _kind.DECLARATION, *args)
|
1046 |
|
|
if isinstance(node.value, astNode.Const) and node.value.value is None:
|
1047 |
|
|
obj = None
|
1048 |
|
|
elif isinstance(node.value, astNode.Name) and node.value.name == 'None':
|
1049 |
|
|
obj = None
|
1050 |
|
|
elif node.value.obj is not None:
|
1051 |
|
|
obj = node.value.obj
|
1052 |
|
|
else:
|
1053 |
|
|
self.raiseError(node, _error.ReturnTypeInfer)
|
1054 |
|
|
if isinstance(obj, intbv) and len(obj) == 0:
|
1055 |
|
|
self.raiseError(node, _error.ReturnIntbvBitWidth)
|
1056 |
|
|
if self.ast.hasReturn:
|
1057 |
|
|
returnObj = self.ast.returnObj
|
1058 |
|
|
if isinstance(obj, type(returnObj)):
|
1059 |
|
|
pass
|
1060 |
|
|
elif isinstance(returnObj, type(obj)):
|
1061 |
|
|
self.ast.returnObj = obj
|
1062 |
|
|
else:
|
1063 |
|
|
self.raiseError(node, _error.ReturnTypeMismatch)
|
1064 |
|
|
if getNrBits(obj) != getNrBits(returnObj):
|
1065 |
|
|
self.raiseError(node, _error.ReturnNrBitsMismatch)
|
1066 |
|
|
else:
|
1067 |
|
|
self.ast.returnObj = obj
|
1068 |
|
|
self.ast.hasReturn = True
|
1069 |
|
|
|
1070 |
|
|
|
1071 |
|
|
def _analyzeTopFunc(func, *args, **kwargs):
|
1072 |
|
|
s = inspect.getsource(func)
|
1073 |
|
|
s = s.lstrip()
|
1074 |
|
|
ast = compiler.parse(s)
|
1075 |
|
|
v = _AnalyzeTopFuncVisitor(*args, **kwargs)
|
1076 |
|
|
compiler.walk(ast, v)
|
1077 |
|
|
return v
|
1078 |
|
|
|
1079 |
|
|
|
1080 |
|
|
class _AnalyzeTopFuncVisitor(object):
|
1081 |
|
|
|
1082 |
|
|
def __init__(self, *args, **kwargs):
|
1083 |
|
|
self.args = args
|
1084 |
|
|
self.kwargs = kwargs
|
1085 |
|
|
self.name = None
|
1086 |
|
|
self.argdict = {}
|
1087 |
|
|
|
1088 |
|
|
def visitFunction(self, node):
|
1089 |
|
|
self.name = node.name
|
1090 |
|
|
argnames = node.argnames
|
1091 |
|
|
i=-1
|
1092 |
|
|
for i, arg in enumerate(self.args):
|
1093 |
|
|
if isinstance(arg, Signal):
|
1094 |
|
|
n = argnames[i]
|
1095 |
|
|
self.argdict[n] = arg
|
1096 |
|
|
for n in argnames[i+1:]:
|
1097 |
|
|
if n in self.kwargs:
|
1098 |
|
|
arg = self.kwargs[n]
|
1099 |
|
|
if isinstance(arg, Signal):
|
1100 |
|
|
self.argdict[n] = arg
|
1101 |
|
|
self.argnames = [n for n in argnames if n in self.argdict]
|
1102 |
|
|
|
1103 |
|
|
|