mirror of
https://github.com/myhdl/myhdl.git
synced 2025-01-24 21:52:56 +08:00
infer check
This commit is contained in:
parent
6d797db44f
commit
beaca96d74
@ -59,6 +59,11 @@ _error.SigMultipleDriven = "Signal has multiple drivers"
|
||||
_error.UndefinedBitWidth = "Signal has undefined bit width"
|
||||
_error.UndrivenSignal = "Signal is not driven"
|
||||
_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.ReturnTypeMismatch="Return type mismatch"
|
||||
_error.ReutrnNrBitsMismatch="Returned nr of bits mismatch"
|
||||
|
||||
def _checkArgs(arglist):
|
||||
for arg in arglist:
|
||||
@ -299,6 +304,19 @@ def getNrBits(obj):
|
||||
return obj._nrbits
|
||||
return None
|
||||
|
||||
|
||||
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
|
||||
|
||||
|
||||
class _AnalyzeVisitor(_ToVerilogMixin):
|
||||
|
||||
def __init__(self, symdict, sourcefile, lineoffset):
|
||||
@ -310,6 +328,8 @@ class _AnalyzeVisitor(_ToVerilogMixin):
|
||||
self.outputs = Set()
|
||||
self.used = Set()
|
||||
self.labelStack = []
|
||||
self.refStack = ReferenceStack()
|
||||
self.globalRefs = Set()
|
||||
|
||||
def getObj(self, node):
|
||||
if hasattr(node, 'obj'):
|
||||
@ -346,19 +366,27 @@ class _AnalyzeVisitor(_ToVerilogMixin):
|
||||
obj = self.getObj(expr)
|
||||
if obj is None:
|
||||
self.raiseError(node, "Cannot infer type or bit width of %s" % n)
|
||||
self.vardict[n] = obj
|
||||
# XXX if n is already in vardict
|
||||
if n in self.vardict:
|
||||
curObj = self.vardict[n]
|
||||
if isinstance(obj, type(curObj)):
|
||||
pass
|
||||
elif isinstance(curObj, type(obj)):
|
||||
self.vardict[n] = obj
|
||||
else:
|
||||
self.raiseError(node, _error.TypeMismatch, n)
|
||||
if getNrBits(obj) != getNrBits(curObj):
|
||||
self.raiseError(node, _error.NrBitsMismatch, n)
|
||||
else:
|
||||
self.vardict[n] = obj
|
||||
else:
|
||||
self.visit(expr, INPUT)
|
||||
|
||||
def visitAssName(self, node, *args):
|
||||
n = node.name
|
||||
# XXX ?
|
||||
if n in self.vardict:
|
||||
return
|
||||
if n in self.used:
|
||||
self.require(node, n not in self.symdict,
|
||||
"Previously used external symbol cannot be locally redeclared: %s" % n)
|
||||
if n in self.globalRefs:
|
||||
self.raiseError(node, _error.UnboundLocal, n)
|
||||
self.refStack.add(n)
|
||||
|
||||
def visitAugAssign(self, node, access=INPUT, *args):
|
||||
self.visit(node.node, INOUT)
|
||||
@ -377,6 +405,8 @@ class _AnalyzeVisitor(_ToVerilogMixin):
|
||||
node.obj = intbv()
|
||||
elif func is len:
|
||||
node.obj = int() # XXX
|
||||
elif func is bool:
|
||||
node.obj = bool()
|
||||
elif func in myhdl.__dict__.values():
|
||||
pass
|
||||
elif func in __builtin__.__dict__.values():
|
||||
@ -422,9 +452,9 @@ class _AnalyzeVisitor(_ToVerilogMixin):
|
||||
node.obj = bool()
|
||||
|
||||
def visitConst(self, node, *args):
|
||||
if isinstance(node.value, bool):
|
||||
node.obj = bool()
|
||||
elif isinstance(node.value, int):
|
||||
## if isinstance(node.value, bool): # bool constants are names ???
|
||||
## node.obj = bool()
|
||||
if isinstance(node.value, int):
|
||||
node.obj = int()
|
||||
else:
|
||||
node.obj = None
|
||||
@ -437,11 +467,13 @@ class _AnalyzeVisitor(_ToVerilogMixin):
|
||||
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.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()
|
||||
@ -457,10 +489,25 @@ class _AnalyzeVisitor(_ToVerilogMixin):
|
||||
if str(type(obj)) == "<class 'myhdl._enum.Enum'>":
|
||||
assert hasattr(obj, node.attrname)
|
||||
node.obj = getattr(obj, node.attrname)
|
||||
|
||||
def visitIf(self, node, *args):
|
||||
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()
|
||||
|
||||
def visitName(self, node, access=INPUT, *args):
|
||||
n = node.name
|
||||
self.used.add(n)
|
||||
if n not in self.refStack:
|
||||
if n in self.vardict:
|
||||
self.raiseError(node, _error.UnboundLocal, n)
|
||||
self.globalRefs.add(n)
|
||||
if n in self.sigdict:
|
||||
if access == INPUT:
|
||||
self.inputs.add(n)
|
||||
@ -475,8 +522,10 @@ class _AnalyzeVisitor(_ToVerilogMixin):
|
||||
node.obj = self.vardict[n]
|
||||
elif n in self.symdict:
|
||||
node.obj = self.symdict[n]
|
||||
else:
|
||||
elif n in __builtin__.__dict__:
|
||||
node.obj = __builtins__[n]
|
||||
else:
|
||||
pass
|
||||
|
||||
def visitReturn(self, node, *args):
|
||||
self.visit(node.value)
|
||||
@ -511,7 +560,9 @@ class _AnalyzeVisitor(_ToVerilogMixin):
|
||||
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()
|
||||
if isinstance(node.test, ast.Const) and \
|
||||
node.test.value == True and \
|
||||
isinstance(node.body.nodes[0], ast.Yield):
|
||||
@ -531,6 +582,7 @@ class _AnalyzeBlockVisitor(_AnalyzeVisitor):
|
||||
sigdict[n] = v
|
||||
|
||||
def visitFunction(self, node, *args):
|
||||
self.refStack.push()
|
||||
print node.code
|
||||
self.visit(node.code)
|
||||
self.kind = ALWAYS
|
||||
@ -542,6 +594,7 @@ class _AnalyzeBlockVisitor(_AnalyzeVisitor):
|
||||
w = node.code.nodes[-1]
|
||||
if not self.getKind(w) == ALWAYS:
|
||||
self.kind = INITIAL
|
||||
self.refStack.pop()
|
||||
|
||||
def visitModule(self, node, *args):
|
||||
self.visit(node.node)
|
||||
@ -571,6 +624,7 @@ class _AnalyzeFuncVisitor(_AnalyzeVisitor):
|
||||
self.returnObj = None
|
||||
|
||||
def visitFunction(self, node, *args):
|
||||
self.refStack.push()
|
||||
argnames = node.argnames
|
||||
for i, arg in enumerate(self.args):
|
||||
if isinstance(arg, ast.Keyword):
|
||||
@ -584,7 +638,7 @@ class _AnalyzeFuncVisitor(_AnalyzeVisitor):
|
||||
if isinstance(v, (Signal, intbv)):
|
||||
self.sigdict[n] = v
|
||||
self.visit(node.code)
|
||||
|
||||
self.refStack.pop()
|
||||
|
||||
def visitReturn(self, node, *args):
|
||||
self.visit(node.value)
|
||||
@ -598,14 +652,14 @@ class _AnalyzeFuncVisitor(_AnalyzeVisitor):
|
||||
self.raiseError(node, "Can't derive return type")
|
||||
if self.hasReturn:
|
||||
returnObj = self.returnObj
|
||||
if getNrBits(obj) != getNrBits(returnObj):
|
||||
self.raiseError(node, "Returned nr of bits is different from before")
|
||||
if isinstance(obj, type(returnObj)):
|
||||
pass
|
||||
elif isinstance(returnObj, type(obj)):
|
||||
self.returnObj = type(obj)
|
||||
self.returnObj = obj
|
||||
else:
|
||||
self.raiseError(node, "Incompatible return type")
|
||||
self.raiseError(node, _error.ReturnTypeMismatch)
|
||||
if getNrBits(obj) != getNrBits(returnObj):
|
||||
self.raiseError(node, _error.ReturnNrBitsMismatch)
|
||||
else:
|
||||
self.returnObj = obj
|
||||
self.hasReturn = True
|
||||
@ -664,7 +718,7 @@ def _writeModuleHeader(f, intf):
|
||||
if s._driven:
|
||||
print >> f, "output %s%s;" % (r, portname)
|
||||
print >> f, "reg %s%s;" % (r, portname)
|
||||
elif s._read:
|
||||
else:
|
||||
print >> f, "input %s%s;" % (r, portname)
|
||||
print >> f
|
||||
|
||||
@ -1060,7 +1114,11 @@ class _ConvertVisitor(_ToVerilogMixin):
|
||||
|
||||
def visitName(self, node):
|
||||
n = node.name
|
||||
if n in self.vardict:
|
||||
if n == 'False':
|
||||
self.write("1'b0")
|
||||
elif n == 'True':
|
||||
self.write("1'b1")
|
||||
elif n in self.vardict:
|
||||
self.write(n)
|
||||
elif node.name in self.symdict:
|
||||
obj = self.symdict[n]
|
||||
@ -1163,7 +1221,6 @@ class _ConvertVisitor(_ToVerilogMixin):
|
||||
|
||||
def visitYield(self, node):
|
||||
self.inYield = True
|
||||
self.writeline()
|
||||
self.write("@ (")
|
||||
self.visit(node.value)
|
||||
self.write(");")
|
||||
@ -1230,6 +1287,8 @@ class _ConvertFunctionVisitor(_ConvertVisitor):
|
||||
elif hasattr(obj, '_nrbits'):
|
||||
self.write("[%s-1:0]" % obj._nrbits)
|
||||
else:
|
||||
print "HERE"
|
||||
print type(obj)
|
||||
raise AssertionError("unexpected type")
|
||||
|
||||
def writeInputDeclarations(self):
|
||||
|
@ -73,6 +73,7 @@ def FramerCtrl_alt(SOF, state, syncFlag, clk, reset_n):
|
||||
|
||||
def FSM():
|
||||
index = intbv(0)[8:] # position in frame
|
||||
state_var = t_State.SEARCH
|
||||
while 1:
|
||||
yield posedge(clk), negedge(reset_n)
|
||||
if reset_n == ACTIVE_LOW:
|
||||
|
209
myhdl/test/toVerilog/test_infer.py
Normal file
209
myhdl/test/toVerilog/test_infer.py
Normal file
@ -0,0 +1,209 @@
|
||||
import os
|
||||
path = os.path
|
||||
import unittest
|
||||
from random import randrange
|
||||
|
||||
from myhdl import *
|
||||
from myhdl._toVerilog import ToVerilogError, _error
|
||||
|
||||
b = c = 2
|
||||
|
||||
def UnboundError1(a, out):
|
||||
while 1:
|
||||
yield a
|
||||
out.next = a + b
|
||||
b = 1
|
||||
|
||||
def UnboundError2(a, out):
|
||||
while 1:
|
||||
yield a
|
||||
if a == 1:
|
||||
c = 1
|
||||
else:
|
||||
out.next = c
|
||||
|
||||
def UnboundError3(a, out):
|
||||
while 1:
|
||||
yield a
|
||||
out.next = a + d
|
||||
d = 1
|
||||
|
||||
def UnboundError4(a, out):
|
||||
while 1:
|
||||
yield a
|
||||
if a == 1:
|
||||
e = 1
|
||||
else:
|
||||
out.next = e
|
||||
|
||||
def InferError1(a, out):
|
||||
yield a
|
||||
b = 2
|
||||
b = intbv(0)[5:]
|
||||
b[:] = 4
|
||||
out.next = b
|
||||
|
||||
def InferError2(a, out):
|
||||
yield a
|
||||
c = intbv(0)[5:]
|
||||
c[:] = 4
|
||||
c = intbv(0)[4:]
|
||||
c[:] = 4
|
||||
out.next = c
|
||||
|
||||
enumType = enum("a", "b", "c")
|
||||
|
||||
def InferError3(a, out):
|
||||
yield a
|
||||
d = enumType.a
|
||||
d = 4
|
||||
out.next = b
|
||||
|
||||
|
||||
|
||||
class TestErrors(unittest.TestCase):
|
||||
|
||||
def check(self, *args):
|
||||
try:
|
||||
i = toVerilog(*args)
|
||||
except ToVerilogError, e:
|
||||
self.assertEqual(e.kind, _error.NotSupported)
|
||||
except:
|
||||
self.fail()
|
||||
else:
|
||||
self.fail()
|
||||
|
||||
def check(self, Infertest, err):
|
||||
a = Signal(intbv(-1)[16:])
|
||||
out_v = Signal(intbv(0)[16:])
|
||||
out = Signal(intbv(0)[16:])
|
||||
try:
|
||||
infertest_inst = toVerilog(Infertest, a, out)
|
||||
except ToVerilogError, e:
|
||||
self.assertEqual(e.kind, err)
|
||||
except:
|
||||
self.fail()
|
||||
else:
|
||||
self.fail()
|
||||
|
||||
def nocheck(self, Infertest, err=None):
|
||||
a = Signal(intbv(-1)[16:])
|
||||
out_v = Signal(intbv(0)[16:])
|
||||
out = Signal(intbv(0)[16:])
|
||||
infertest_inst = toVerilog(Infertest, a, out)
|
||||
|
||||
|
||||
def testUnboundError1(self):
|
||||
sim = self.check(UnboundError1, _error.UnboundLocal)
|
||||
|
||||
def testUnboundError2(self):
|
||||
sim = self.check(UnboundError2, _error.UnboundLocal)
|
||||
|
||||
def testUnboundError3(self):
|
||||
sim = self.check(UnboundError3, _error.UnboundLocal)
|
||||
|
||||
def testUnboundError4(self):
|
||||
sim = self.check(UnboundError4, _error.UnboundLocal)
|
||||
|
||||
def testInferError1(self):
|
||||
sim = self.check(InferError1, _error.TypeMismatch)
|
||||
|
||||
def testInferError2(self):
|
||||
sim = self.check(InferError2, _error.NrBitsMismatch)
|
||||
|
||||
def testInferError3(self):
|
||||
sim = self.check(InferError3, _error.TypeMismatch)
|
||||
|
||||
|
||||
|
||||
|
||||
def Infer1(a, out):
|
||||
yield a
|
||||
c = 5
|
||||
c = a < 4
|
||||
c = bool(0)
|
||||
c = False
|
||||
c = True
|
||||
out.next = c
|
||||
|
||||
def Infer2(a, out):
|
||||
yield a
|
||||
c = a < 4
|
||||
c = bool(0)
|
||||
c = False
|
||||
c = True
|
||||
c = 5
|
||||
out.next = c
|
||||
|
||||
def Infer3Func(a):
|
||||
if True:
|
||||
return a > 0
|
||||
else:
|
||||
return 5
|
||||
|
||||
def Infer3(a, out):
|
||||
yield a
|
||||
out.next = Infer3Func(a)
|
||||
|
||||
def Infer4Func(a):
|
||||
if True:
|
||||
return 6
|
||||
else:
|
||||
return a < 3
|
||||
|
||||
def Infer4(a, out):
|
||||
yield a
|
||||
out.next = Infer4Func(a)
|
||||
|
||||
|
||||
|
||||
objfile = "infertest.o"
|
||||
analyze_cmd = "iverilog -o %s infertest_inst.v tb_infertest_inst.v" % objfile
|
||||
simulate_cmd = "vvp -m ../../../cosimulation/icarus/myhdl.vpi %s" % objfile
|
||||
|
||||
def Infertest_v(a, out):
|
||||
if path.exists(objfile):
|
||||
os.remove(objfile)
|
||||
os.system(analyze_cmd)
|
||||
return Cosimulation(simulate_cmd, **locals())
|
||||
|
||||
class TestInfer(unittest.TestCase):
|
||||
|
||||
def bench(self, Infertest):
|
||||
|
||||
a = Signal(intbv(-1)[16:])
|
||||
out_v = Signal(intbv(0)[16:])
|
||||
out = Signal(intbv(0)[16:])
|
||||
|
||||
infertest_inst = toVerilog(Infertest, a, out)
|
||||
# infertest_inst = Infertest(hec, header)
|
||||
infertest_v_inst = Infertest_v(a, out_v)
|
||||
|
||||
def stimulus():
|
||||
a.next = 1
|
||||
yield delay(10)
|
||||
print "%s %s" % (out, out_v)
|
||||
self.assertEqual(out, out_v)
|
||||
|
||||
return stimulus(), infertest_inst, infertest_v_inst
|
||||
|
||||
## def testInfer1(self):
|
||||
## sim = self.bench(Infer1)
|
||||
## Simulation(sim).run()
|
||||
|
||||
## def testInfer2(self):
|
||||
## sim = self.bench(Infer2)
|
||||
## Simulation(sim).run()
|
||||
|
||||
## def testInfer3(self):
|
||||
## sim = self.bench(Infer3)
|
||||
## Simulation(sim).run()
|
||||
|
||||
def testInfer4(self):
|
||||
sim = self.bench(Infer4)
|
||||
Simulation(sim).run()
|
||||
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
Loading…
x
Reference in New Issue
Block a user