From 61047c189c24dae7de74240318f14505437295b2 Mon Sep 17 00:00:00 2001 From: Keerthan Jaic Date: Mon, 13 Jul 2015 04:53:12 -0400 Subject: [PATCH 01/11] move SigNameVisitor out of always_comb --- myhdl/_always_comb.py | 94 +------------------------------------ myhdl/_visitors.py | 105 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 106 insertions(+), 93 deletions(-) create mode 100644 myhdl/_visitors.py diff --git a/myhdl/_always_comb.py b/myhdl/_always_comb.py index 3bfbefcf..3d432402 100644 --- a/myhdl/_always_comb.py +++ b/myhdl/_always_comb.py @@ -33,6 +33,7 @@ from myhdl._cell_deref import _cell_deref from myhdl._Waiter import _Waiter, _SignalWaiter, _SignalTupleWaiter from myhdl._instance import _Instantiator from myhdl._resolverefs import _AttrRefTransformer +from myhdl._visitors import _SigNameVisitor class _error: pass @@ -67,99 +68,6 @@ def always_comb(func): return c -INPUT, OUTPUT, INOUT = range(3) - - - -class _SigNameVisitor(ast.NodeVisitor): - def __init__(self, symdict): - self.inputs = set() - self.outputs = set() - self.toplevel = 1 - self.symdict = symdict - self.context = INPUT - - def visit_Module(self, node): - inputs = self.inputs - outputs = self.outputs - for n in node.body: - self.visit(n) - for n in inputs: - if n in outputs: - raise AlwaysCombError(_error.SignalAsInout % n) - - def visit_FunctionDef(self, node): - if self.toplevel: - self.toplevel = 0 # skip embedded functions - for n in node.body: - self.visit(n) - else: - raise AlwaysCombError(_error.EmbeddedFunction) - - def visit_If(self, node): - if not node.orelse: - if isinstance(node.test, ast.Name) and \ - node.test.id == '__debug__': - return # skip - self.generic_visit(node) - - def visit_Name(self, node): - id = node.id - if id not in self.symdict: - return - s = self.symdict[id] - if isinstance(s, _Signal) or _isListOfSigs(s): - if self.context == INPUT: - self.inputs.add(id) - elif self.context == OUTPUT: - self.outputs.add(id) - elif self.context == INOUT: - raise AlwaysCombError(_error.SignalAsInout % id) - else: - raise AssertionError("bug in always_comb") - - def visit_Assign(self, node): - self.context = OUTPUT - for n in node.targets: - self.visit(n) - self.context = INPUT - self.visit(node.value) - - def visit_Attribute(self, node): - self.visit(node.value) - - def visit_Call(self, node): - fn = None - if isinstance(node.func, ast.Name): - fn = node.func.id - if fn == "len": - pass - else: - self.generic_visit(node) - - - def visit_Subscript(self, node, access=INPUT): - self.visit(node.value) - self.context = INPUT - self.visit(node.slice) - - def visit_AugAssign(self, node, access=INPUT): - self.context = INOUT - self.visit(node.target) - self.context = INPUT - self.visit(node.value) - - def visit_ClassDef(self, node): - pass # skip - - def visit_Exec(self, node): - pass # skip - - def visit_Print(self, node): - pass # skip - - - class _AlwaysComb(_Instantiator): # def __init__(self, func, symdict): diff --git a/myhdl/_visitors.py b/myhdl/_visitors.py new file mode 100644 index 00000000..1333c4db --- /dev/null +++ b/myhdl/_visitors.py @@ -0,0 +1,105 @@ +import ast + +from myhdl import AlwaysCombError +from myhdl._Signal import _Signal, _isListOfSigs + +class _error: + pass + +_error.ArgType = "always_comb argument should be a classic function" +_error.NrOfArgs = "always_comb argument should be a function without arguments" +_error.Scope = "always_comb argument should be a local function" +_error.SignalAsInout = "signal (%s) used as inout in always_comb function argument" +_error.EmbeddedFunction = "embedded functions in always_comb function argument not supported" +_error.EmptySensitivityList= "sensitivity list is empty" + +INPUT, OUTPUT, INOUT = range(3) + + + +class _SigNameVisitor(ast.NodeVisitor): + def __init__(self, symdict): + self.inputs = set() + self.outputs = set() + self.toplevel = 1 + self.symdict = symdict + self.context = INPUT + + def visit_Module(self, node): + inputs = self.inputs + outputs = self.outputs + for n in node.body: + self.visit(n) + for n in inputs: + if n in outputs: + raise AlwaysCombError(_error.SignalAsInout % n) + + def visit_FunctionDef(self, node): + if self.toplevel: + self.toplevel = 0 # skip embedded functions + for n in node.body: + self.visit(n) + else: + raise AlwaysCombError(_error.EmbeddedFunction) + + def visit_If(self, node): + if not node.orelse: + if isinstance(node.test, ast.Name) and \ + node.test.id == '__debug__': + return # skip + self.generic_visit(node) + + def visit_Name(self, node): + id = node.id + if id not in self.symdict: + return + s = self.symdict[id] + if isinstance(s, _Signal) or _isListOfSigs(s): + if self.context == INPUT: + self.inputs.add(id) + elif self.context == OUTPUT: + self.outputs.add(id) + elif self.context == INOUT: + raise AlwaysCombError(_error.SignalAsInout % id) + else: + raise AssertionError("bug in always_comb") + + def visit_Assign(self, node): + self.context = OUTPUT + for n in node.targets: + self.visit(n) + self.context = INPUT + self.visit(node.value) + + def visit_Attribute(self, node): + self.visit(node.value) + + def visit_Call(self, node): + fn = None + if isinstance(node.func, ast.Name): + fn = node.func.id + if fn == "len": + pass + else: + self.generic_visit(node) + + + def visit_Subscript(self, node, access=INPUT): + self.visit(node.value) + self.context = INPUT + self.visit(node.slice) + + def visit_AugAssign(self, node, access=INPUT): + self.context = INOUT + self.visit(node.target) + self.context = INPUT + self.visit(node.value) + + def visit_ClassDef(self, node): + pass # skip + + def visit_Exec(self, node): + pass # skip + + def visit_Print(self, node): + pass # skip From c4ca71f40fa6fd41cc13b36fcb7677ed8d779f8f Mon Sep 17 00:00:00 2001 From: Keerthan Jaic Date: Mon, 13 Jul 2015 05:02:34 -0400 Subject: [PATCH 02/11] remove use of adhoc input,output,inout enum --- myhdl/_always_comb.py | 4 ++-- myhdl/_visitors.py | 44 +++++++++++++++++++++---------------------- 2 files changed, 23 insertions(+), 25 deletions(-) diff --git a/myhdl/_always_comb.py b/myhdl/_always_comb.py index 3d432402..41e67f10 100644 --- a/myhdl/_always_comb.py +++ b/myhdl/_always_comb.py @@ -110,8 +110,8 @@ class _AlwaysComb(_Instantiator): v.visit(tree) v = _SigNameVisitor(self.symdict) v.visit(tree) - self.inputs = v.inputs - self.outputs = v.outputs + self.inputs = v.results['input'] + self.outputs = v.results['output'] senslist = [] for n in self.inputs: s = self.symdict[n] diff --git a/myhdl/_visitors.py b/myhdl/_visitors.py index 1333c4db..02bbc827 100644 --- a/myhdl/_visitors.py +++ b/myhdl/_visitors.py @@ -3,6 +3,7 @@ import ast from myhdl import AlwaysCombError from myhdl._Signal import _Signal, _isListOfSigs + class _error: pass @@ -13,21 +14,20 @@ _error.SignalAsInout = "signal (%s) used as inout in always_comb function argume _error.EmbeddedFunction = "embedded functions in always_comb function argument not supported" _error.EmptySensitivityList= "sensitivity list is empty" -INPUT, OUTPUT, INOUT = range(3) - - class _SigNameVisitor(ast.NodeVisitor): def __init__(self, symdict): - self.inputs = set() - self.outputs = set() self.toplevel = 1 self.symdict = symdict - self.context = INPUT + self.results = { + 'input': set(), + 'output': set() + } + self.context = 'input' def visit_Module(self, node): - inputs = self.inputs - outputs = self.outputs + inputs = self.results['input'] + outputs = self.results['output'] for n in node.body: self.visit(n) for n in inputs: @@ -36,7 +36,7 @@ class _SigNameVisitor(ast.NodeVisitor): def visit_FunctionDef(self, node): if self.toplevel: - self.toplevel = 0 # skip embedded functions + self.toplevel = 0 # skip embedded functions for n in node.body: self.visit(n) else: @@ -46,7 +46,7 @@ class _SigNameVisitor(ast.NodeVisitor): if not node.orelse: if isinstance(node.test, ast.Name) and \ node.test.id == '__debug__': - return # skip + return # skip self.generic_visit(node) def visit_Name(self, node): @@ -55,20 +55,19 @@ class _SigNameVisitor(ast.NodeVisitor): return s = self.symdict[id] if isinstance(s, _Signal) or _isListOfSigs(s): - if self.context == INPUT: - self.inputs.add(id) - elif self.context == OUTPUT: - self.outputs.add(id) - elif self.context == INOUT: + if self.context in ('input', 'output'): + self.results[self.context].add(id) + elif self.context == 'inout': raise AlwaysCombError(_error.SignalAsInout % id) else: + print(self.context) raise AssertionError("bug in always_comb") def visit_Assign(self, node): - self.context = OUTPUT + self.context = 'output' for n in node.targets: self.visit(n) - self.context = INPUT + self.context = 'input' self.visit(node.value) def visit_Attribute(self, node): @@ -82,17 +81,16 @@ class _SigNameVisitor(ast.NodeVisitor): pass else: self.generic_visit(node) - - def visit_Subscript(self, node, access=INPUT): + def visit_Subscript(self, node, access='input'): self.visit(node.value) - self.context = INPUT + self.context = 'input' self.visit(node.slice) - def visit_AugAssign(self, node, access=INPUT): - self.context = INOUT + def visit_AugAssign(self, node, access='input'): + self.context = 'inout' self.visit(node.target) - self.context = INPUT + self.context = 'input' self.visit(node.value) def visit_ClassDef(self, node): From cf0267c8ef9f3c6fcf92db5330c333258421d1b7 Mon Sep 17 00:00:00 2001 From: Keerthan Jaic Date: Mon, 13 Jul 2015 06:02:30 -0400 Subject: [PATCH 03/11] move exception raising out of SigNameVisitor Raise the exceptions in always_comb instead. This allows SigNameVisitor to be shared with always_seq --- myhdl/_always_comb.py | 8 ++++++++ myhdl/_visitors.py | 25 +++++-------------------- myhdl/test/core/test_always_comb.py | 4 ++-- 3 files changed, 15 insertions(+), 22 deletions(-) diff --git a/myhdl/_always_comb.py b/myhdl/_always_comb.py index 41e67f10..4fb8cd0c 100644 --- a/myhdl/_always_comb.py +++ b/myhdl/_always_comb.py @@ -112,6 +112,14 @@ class _AlwaysComb(_Instantiator): v.visit(tree) self.inputs = v.results['input'] self.outputs = v.results['output'] + + inouts = v.results['inout'] | self.inputs.intersection(self.outputs) + if inouts: + raise AlwaysCombError(_error.SignalAsInout % inouts) + + if v.results['embedded_func']: + raise AlwaysCombError(_error.EmbeddedFunction) + senslist = [] for n in self.inputs: s = self.symdict[n] diff --git a/myhdl/_visitors.py b/myhdl/_visitors.py index 02bbc827..d9e5c0d6 100644 --- a/myhdl/_visitors.py +++ b/myhdl/_visitors.py @@ -1,27 +1,17 @@ import ast -from myhdl import AlwaysCombError from myhdl._Signal import _Signal, _isListOfSigs -class _error: - pass - -_error.ArgType = "always_comb argument should be a classic function" -_error.NrOfArgs = "always_comb argument should be a function without arguments" -_error.Scope = "always_comb argument should be a local function" -_error.SignalAsInout = "signal (%s) used as inout in always_comb function argument" -_error.EmbeddedFunction = "embedded functions in always_comb function argument not supported" -_error.EmptySensitivityList= "sensitivity list is empty" - - class _SigNameVisitor(ast.NodeVisitor): def __init__(self, symdict): self.toplevel = 1 self.symdict = symdict self.results = { 'input': set(), - 'output': set() + 'output': set(), + 'inout': set(), + 'embedded_func': set() } self.context = 'input' @@ -30,9 +20,6 @@ class _SigNameVisitor(ast.NodeVisitor): outputs = self.results['output'] for n in node.body: self.visit(n) - for n in inputs: - if n in outputs: - raise AlwaysCombError(_error.SignalAsInout % n) def visit_FunctionDef(self, node): if self.toplevel: @@ -40,7 +27,7 @@ class _SigNameVisitor(ast.NodeVisitor): for n in node.body: self.visit(n) else: - raise AlwaysCombError(_error.EmbeddedFunction) + self.results['embedded_func'] = node.name def visit_If(self, node): if not node.orelse: @@ -55,10 +42,8 @@ class _SigNameVisitor(ast.NodeVisitor): return s = self.symdict[id] if isinstance(s, _Signal) or _isListOfSigs(s): - if self.context in ('input', 'output'): + if self.context in ('input', 'output', 'inout'): self.results[self.context].add(id) - elif self.context == 'inout': - raise AlwaysCombError(_error.SignalAsInout % id) else: print(self.context) raise AssertionError("bug in always_comb") diff --git a/myhdl/test/core/test_always_comb.py b/myhdl/test/core/test_always_comb.py index b3840c5a..b0a73b96 100644 --- a/myhdl/test/core/test_always_comb.py +++ b/myhdl/test/core/test_always_comb.py @@ -122,7 +122,7 @@ class TestAlwaysCombCompilation: def h(): c.next += 1 a += 1 - with raises_kind(AlwaysCombError, _error.SignalAsInout % "c"): + with raises_kind(AlwaysCombError, _error.SignalAsInout % {'c'}): g = always_comb(h).gen def testInfer6(self): @@ -131,7 +131,7 @@ class TestAlwaysCombCompilation: def h(): c.next = a x.next = c - with raises_kind(AlwaysCombError, _error.SignalAsInout % "c"): + with raises_kind(AlwaysCombError, _error.SignalAsInout % {'c'}): g = always_comb(h).gen def testInfer7(self): From 6bd068632a38d6cfc1f7d8bafe3c0f29baa668df Mon Sep 17 00:00:00 2001 From: Keerthan Jaic Date: Mon, 13 Jul 2015 06:27:48 -0400 Subject: [PATCH 04/11] custom raises kind __tracebackhide__ does not work with the contextmanager decorator. This custom raises_kind implementation uses __tracebackhide__ to provide better reporting when tests fail. --- myhdl/test/core/utils.py | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/myhdl/test/core/utils.py b/myhdl/test/core/utils.py index b9b42a80..af9aee44 100644 --- a/myhdl/test/core/utils.py +++ b/myhdl/test/core/utils.py @@ -1,10 +1,17 @@ -from contextlib import contextmanager - import pytest -@contextmanager -def raises_kind(exc, kind): - with pytest.raises(exc) as excinfo: - yield - assert excinfo.value.kind == kind +class raises_kind(object): + def __init__(self, exc, kind): + self.exc = exc + self.kind = kind + + def __enter__(self): + return None + + def __exit__(self, *tp): + __tracebackhide__ = True + if tp[0] is None: + pytest.fail("DID NOT RAISE") + assert tp[1].kind == self.kind + return issubclass(tp[0], self.exc) From 2db353b0d023ee6a8828007d8f42bb7fa4ddcb13 Mon Sep 17 00:00:00 2001 From: Keerthan Jaic Date: Mon, 13 Jul 2015 06:40:41 -0400 Subject: [PATCH 05/11] always_seq: reuse SigNameVisitor from _visitors --- myhdl/_always_seq.py | 95 +++++--------------------------------------- myhdl/_visitors.py | 3 +- 2 files changed, 11 insertions(+), 87 deletions(-) diff --git a/myhdl/_always_seq.py b/myhdl/_always_seq.py index bd6f87b7..ebea06f1 100644 --- a/myhdl/_always_seq.py +++ b/myhdl/_always_seq.py @@ -34,6 +34,7 @@ from myhdl._Signal import _Signal, _WaiterList,_isListOfSigs from myhdl._Waiter import _Waiter, _EdgeWaiter, _EdgeTupleWaiter from myhdl._instance import _Instantiator from myhdl._resolverefs import _AttrRefTransformer +from myhdl._visitors import _SigNameVisitor # evacuate this later AlwaysSeqError = AlwaysError @@ -131,9 +132,16 @@ class _AlwaysSeq(_Instantiator): v.visit(tree) v = _SigNameVisitor(self.symdict) v.visit(tree) + + if v.results['inout']: + raise AlwaysSeqError(_error.SigAugAssign, v.results['inout']) + + if v.results['embedded_func']: + raise AlwaysSeqError(_error.EmbeddedFunction) + sigregs = self.sigregs = [] varregs = self.varregs = [] - for n in v.outputs: + for n in v.results['output']: reg = self.symdict[n] if isinstance(reg, _Signal): sigregs.append(reg) @@ -178,88 +186,3 @@ class _AlwaysSeq(_Instantiator): while 1: yield senslist func() - - -# similar to always_comb, calls for refactoring -# note: make a difference between augmented assign and inout signals - -INPUT, OUTPUT, INOUT = range(3) - -class _SigNameVisitor(ast.NodeVisitor): - def __init__(self, symdict): - self.inputs = set() - self.outputs = set() - self.toplevel = 1 - self.symdict = symdict - self.context = INPUT - - def visit_Module(self, node): - - for n in node.body: - self.visit(n) - - def visit_FunctionDef(self, node): - if self.toplevel: - self.toplevel = 0 # skip embedded functions - for n in node.body: - self.visit(n) - else: - raise AlwaysSeqError(_error.EmbeddedFunction) - - def visit_If(self, node): - if not node.orelse: - if isinstance(node.test, ast.Name) and \ - node.test.id == '__debug__': - return # skip - self.generic_visit(node) - - def visit_Name(self, node): - id = node.id - if id not in self.symdict: - return - s = self.symdict[id] - if isinstance(s, (_Signal, intbv)) or _isListOfSigs(s): - if self.context == INPUT: - self.inputs.add(id) - elif self.context == OUTPUT: - self.outputs.add(id) - elif self.context == INOUT: - raise AlwaysSeqError(_error.SigAugAssign, id) - else: - raise AssertionError("bug in always_seq") - - def visit_Assign(self, node): - self.context = OUTPUT - for n in node.targets: - self.visit(n) - self.context = INPUT - self.visit(node.value) - - def visit_Attribute(self, node): - self.visit(node.value) - - def visit_Subscript(self, node, access=INPUT): - self.visit(node.value) - self.context = INPUT - self.visit(node.slice) - - def visit_AugAssign(self, node, access=INPUT): - self.context = INOUT - self.visit(node.target) - self.context = INPUT - self.visit(node.value) - - def visit_ClassDef(self, node): - pass # skip - - def visit_Exec(self, node): - pass # skip - - def visit_Print(self, node): - pass # skip - - - - - - diff --git a/myhdl/_visitors.py b/myhdl/_visitors.py index d9e5c0d6..1eabf51e 100644 --- a/myhdl/_visitors.py +++ b/myhdl/_visitors.py @@ -1,5 +1,6 @@ import ast +from myhdl import intbv from myhdl._Signal import _Signal, _isListOfSigs @@ -41,7 +42,7 @@ class _SigNameVisitor(ast.NodeVisitor): if id not in self.symdict: return s = self.symdict[id] - if isinstance(s, _Signal) or _isListOfSigs(s): + if isinstance(s, (_Signal, intbv)) or _isListOfSigs(s): if self.context in ('input', 'output', 'inout'): self.results[self.context].add(id) else: From 91fff9974a4e8cc1f77e1999a4a6f8b037dda28e Mon Sep 17 00:00:00 2001 From: Keerthan Jaic Date: Mon, 13 Jul 2015 06:47:47 -0400 Subject: [PATCH 06/11] use old style set definition for py2.6 --- myhdl/test/core/test_always_comb.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/myhdl/test/core/test_always_comb.py b/myhdl/test/core/test_always_comb.py index b0a73b96..a6be76d7 100644 --- a/myhdl/test/core/test_always_comb.py +++ b/myhdl/test/core/test_always_comb.py @@ -122,7 +122,7 @@ class TestAlwaysCombCompilation: def h(): c.next += 1 a += 1 - with raises_kind(AlwaysCombError, _error.SignalAsInout % {'c'}): + with raises_kind(AlwaysCombError, _error.SignalAsInout % set('c')): g = always_comb(h).gen def testInfer6(self): @@ -131,7 +131,7 @@ class TestAlwaysCombCompilation: def h(): c.next = a x.next = c - with raises_kind(AlwaysCombError, _error.SignalAsInout % {'c'}): + with raises_kind(AlwaysCombError, _error.SignalAsInout % set('c')): g = always_comb(h).gen def testInfer7(self): From 63d7fce2af39156e8c676c03228b4d8e0444ead2 Mon Sep 17 00:00:00 2001 From: Keerthan Jaic Date: Mon, 13 Jul 2015 07:14:30 -0400 Subject: [PATCH 07/11] reuse _Instantiator init in _Always --- myhdl/_always.py | 24 +++++++++++------------- myhdl/_instance.py | 13 ++++++++----- 2 files changed, 19 insertions(+), 18 deletions(-) diff --git a/myhdl/_always.py b/myhdl/_always.py index 1dbe033d..44ebcd01 100644 --- a/myhdl/_always.py +++ b/myhdl/_always.py @@ -58,28 +58,28 @@ def always(*args): raise AlwaysError(_error.NrOfArgs) return _Always(func, args) return _always_decorator - + class _Always(_Instantiator): - def __init__(self, func, args): + def __init__(self, func, senslist): self.func = func - self.senslist = tuple(args) - self.gen = self.genfunc() - + self.senslist = tuple(senslist) + super(_Always, self).__init__(self.genfunc) + + @property + def _waiter(self): # infer appropriate waiter class # first infer base type of arguments for t in (_Signal, _WaiterList, delay): - if isinstance(args[0], t): + if isinstance(self.senslist[0], t): bt = t - for arg in args[1:]: - if not isinstance(arg, bt): + for s in self.senslist[1:]: + if not isinstance(s, bt): bt = None break # now set waiter class - W = _Waiter - if bt is delay: W = _DelayWaiter elif len(self.senslist) == 1: @@ -93,8 +93,7 @@ class _Always(_Instantiator): elif bt is _WaiterList: W = _EdgeTupleWaiter - self.waiter = W(self.gen) - + return W def genfunc(self): senslist = self.senslist @@ -104,4 +103,3 @@ class _Always(_Instantiator): while 1: yield senslist func() - diff --git a/myhdl/_instance.py b/myhdl/_instance.py index 956c4e65..701458e6 100644 --- a/myhdl/_instance.py +++ b/myhdl/_instance.py @@ -44,8 +44,11 @@ def instance(genFunc): class _Instantiator(object): - def __init__(self, genFunc): - self.genfunc = genFunc - self.gen = genFunc() - self.waiter = _inferWaiter(self.gen) - + def __init__(self, genfunc): + self.genfunc = genfunc + self.gen = genfunc() + self.waiter = self._waiter(self.gen) + + @property + def _waiter(self): + return _inferWaiter From 9fda87bbecba5dcf3880b2bd17f4b86f1bdd6e28 Mon Sep 17 00:00:00 2001 From: Keerthan Jaic Date: Mon, 13 Jul 2015 08:02:19 -0400 Subject: [PATCH 08/11] make always_comb inherit from always --- myhdl/_always_comb.py | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/myhdl/_always_comb.py b/myhdl/_always_comb.py index 4fb8cd0c..07241611 100644 --- a/myhdl/_always_comb.py +++ b/myhdl/_always_comb.py @@ -32,6 +32,7 @@ from myhdl._util import _isGenFunc, _dedent from myhdl._cell_deref import _cell_deref from myhdl._Waiter import _Waiter, _SignalWaiter, _SignalTupleWaiter from myhdl._instance import _Instantiator +from myhdl._always import _Always from myhdl._resolverefs import _AttrRefTransformer from myhdl._visitors import _SigNameVisitor @@ -68,7 +69,8 @@ def always_comb(func): return c -class _AlwaysComb(_Instantiator): +# class _AlwaysComb(_Instantiator): +class _AlwaysComb(_Always): # def __init__(self, func, symdict): # self.func = func @@ -100,7 +102,6 @@ class _AlwaysComb(_Instantiator): # self.waiter = W(self.gen) def __init__(self, func, symdict): - self.func = func self.symdict = symdict s = inspect.getsource(func) s = _dedent(s) @@ -128,16 +129,10 @@ class _AlwaysComb(_Instantiator): else: # list of sigs senslist.extend(s) self.senslist = tuple(senslist) - self.gen = self.genfunc() if len(self.senslist) == 0: raise AlwaysCombError(_error.EmptySensitivityList) - if len(self.senslist) == 1: - W = _SignalWaiter - else: - W = _SignalTupleWaiter - self.waiter = W(self.gen) - + super(_AlwaysComb, self).__init__(func, senslist) def genfunc(self): senslist = self.senslist From a402480c7b0e65dc1a927a354fb74a6bdc33d560 Mon Sep 17 00:00:00 2001 From: Keerthan Jaic Date: Mon, 13 Jul 2015 08:07:07 -0400 Subject: [PATCH 09/11] make always_seq inherit from always --- myhdl/_always_seq.py | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/myhdl/_always_seq.py b/myhdl/_always_seq.py index ebea06f1..f219b0c3 100644 --- a/myhdl/_always_seq.py +++ b/myhdl/_always_seq.py @@ -32,7 +32,7 @@ from myhdl._cell_deref import _cell_deref from myhdl._delay import delay from myhdl._Signal import _Signal, _WaiterList,_isListOfSigs from myhdl._Waiter import _Waiter, _EdgeWaiter, _EdgeTupleWaiter -from myhdl._instance import _Instantiator +from myhdl._always import _Always from myhdl._resolverefs import _AttrRefTransformer from myhdl._visitors import _SigNameVisitor @@ -83,13 +83,13 @@ def always_seq(edge, reset): return _always_seq_decorator -class _AlwaysSeq(_Instantiator): +class _AlwaysSeq(_Always): def __init__(self, func, edge, reset): - self.func = func - self.senslist = senslist = [edge] + senslist = [edge] self.reset = reset if reset is not None: + self.genfunc = self.genfunc_reset active = self.reset.active async = self.reset.async if async: @@ -97,14 +97,10 @@ class _AlwaysSeq(_Instantiator): senslist.append(reset.posedge) else: senslist.append(reset.negedge) - self.gen = self.genfunc() else: - self.gen = self.genfunc_no_reset() - if len(self.senslist) == 1: - W = _EdgeWaiter - else: - W = _EdgeTupleWaiter - self.waiter = W(self.gen) + self.genfunc = self.genfunc_no_reset + + super(_AlwaysSeq, self).__init__(func, senslist) # find symdict # similar to always_comb, but in class constructor @@ -152,7 +148,6 @@ class _AlwaysSeq(_Instantiator): for e in reg: sigregs.append(e) - def reset_sigs(self): for s in self.sigregs: s.next = s._init @@ -163,7 +158,7 @@ class _AlwaysSeq(_Instantiator): n, reg, init = v reg._val = init - def genfunc(self): + def genfunc_reset(self): senslist = self.senslist if len(senslist) == 1: senslist = senslist[0] From c5bf1221330c603efc13d8740c1d037a1776bfda Mon Sep 17 00:00:00 2001 From: Keerthan Jaic Date: Mon, 13 Jul 2015 08:34:16 -0400 Subject: [PATCH 10/11] centralize ast acces as an attr of instantiators --- myhdl/_always.py | 6 +++++- myhdl/_instance.py | 6 +++++- myhdl/_resolverefs.py | 6 ++---- myhdl/conversion/_analyze.py | 4 ++-- 4 files changed, 14 insertions(+), 8 deletions(-) diff --git a/myhdl/_always.py b/myhdl/_always.py index 44ebcd01..719f0a8c 100644 --- a/myhdl/_always.py +++ b/myhdl/_always.py @@ -24,7 +24,7 @@ from __future__ import absolute_import from types import FunctionType from myhdl import AlwaysError -from myhdl._util import _isGenFunc +from myhdl._util import _isGenFunc, _makeAST from myhdl._delay import delay from myhdl._Signal import _Signal, _WaiterList, posedge, negedge from myhdl._Waiter import _Waiter, _SignalWaiter, _SignalTupleWaiter, \ @@ -95,6 +95,10 @@ class _Always(_Instantiator): return W + @property + def ast(self): + return _makeAST(self.func) + def genfunc(self): senslist = self.senslist if len(senslist) == 1: diff --git a/myhdl/_instance.py b/myhdl/_instance.py index 701458e6..40efa1b5 100644 --- a/myhdl/_instance.py +++ b/myhdl/_instance.py @@ -24,7 +24,7 @@ from __future__ import absolute_import from types import FunctionType from myhdl import InstanceError -from myhdl._util import _isGenFunc +from myhdl._util import _isGenFunc, _makeAST from myhdl._Waiter import _inferWaiter class _error: @@ -52,3 +52,7 @@ class _Instantiator(object): @property def _waiter(self): return _inferWaiter + + @property + def ast(self): + return _makeAST(self.gen.gi_frame) diff --git a/myhdl/_resolverefs.py b/myhdl/_resolverefs.py index 247b6725..e824f181 100644 --- a/myhdl/_resolverefs.py +++ b/myhdl/_resolverefs.py @@ -3,7 +3,7 @@ import ast import itertools from types import FunctionType -from myhdl._util import _flatten, _makeAST, _genfunc +from myhdl._util import _flatten from myhdl._enum import EnumType from myhdl._Signal import SignalType @@ -18,9 +18,7 @@ def _resolveRefs(symdict, arg): data.symdict = symdict v = _AttrRefTransformer(data) for gen in gens: - func = _genfunc(gen) - tree = _makeAST(func) - v.visit(tree) + v.visit(gen.ast) return data.objlist #TODO: Refactor this into two separate nodetransformers, since _resolveRefs diff --git a/myhdl/conversion/_analyze.py b/myhdl/conversion/_analyze.py index 42502a55..22f998da 100644 --- a/myhdl/conversion/_analyze.py +++ b/myhdl/conversion/_analyze.py @@ -145,7 +145,7 @@ def _analyzeGens(top, absnames): tree = g elif isinstance(g, (_AlwaysComb, _AlwaysSeq, _Always)): f = g.func - tree = _makeAST(f) + tree = g.ast tree.symdict = f.__globals__.copy() tree.callstack = [] # handle free variables @@ -171,7 +171,7 @@ def _analyzeGens(top, absnames): v.visit(tree) else: # @instance f = g.gen.gi_frame - tree = _makeAST(f) + tree = g.ast tree.symdict = f.f_globals.copy() tree.symdict.update(f.f_locals) tree.nonlocaldict = {} From f93d92a43adcfa67922c43e2566b73fb796c4ecc Mon Sep 17 00:00:00 2001 From: Keerthan Jaic Date: Wed, 22 Jul 2015 05:10:14 -0400 Subject: [PATCH 11/11] make waiter a property of Instantiators Rather than storing the waiter as an attribute, store it as a property. This reduces unnecessary computation while converting. --- myhdl/_always.py | 1 - myhdl/_instance.py | 4 +++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/myhdl/_always.py b/myhdl/_always.py index 719f0a8c..598734d1 100644 --- a/myhdl/_always.py +++ b/myhdl/_always.py @@ -67,7 +67,6 @@ class _Always(_Instantiator): self.senslist = tuple(senslist) super(_Always, self).__init__(self.genfunc) - @property def _waiter(self): # infer appropriate waiter class # first infer base type of arguments diff --git a/myhdl/_instance.py b/myhdl/_instance.py index 40efa1b5..369e758d 100644 --- a/myhdl/_instance.py +++ b/myhdl/_instance.py @@ -47,9 +47,11 @@ class _Instantiator(object): def __init__(self, genfunc): self.genfunc = genfunc self.gen = genfunc() - self.waiter = self._waiter(self.gen) @property + def waiter(self): + return self._waiter()(self.gen) + def _waiter(self): return _inferWaiter