From 1182071e2906a0b74bd684f7e6a90431bfc40bd2 Mon Sep 17 00:00:00 2001 From: Jan Decaluwe Date: Thu, 11 Feb 2016 11:27:44 +0100 Subject: [PATCH] Make the module decorator work on methods; migrate test --- myhdl/_module.py | 18 ++++++++++++++---- myhdl/test/conversion/general/test_method.py | 13 ++++++++++--- 2 files changed, 24 insertions(+), 7 deletions(-) diff --git a/myhdl/_module.py b/myhdl/_module.py index 572043f8..ffcd43b2 100644 --- a/myhdl/_module.py +++ b/myhdl/_module.py @@ -54,14 +54,14 @@ def _getCallInfo(): 3: the function that defines instances 4: the caller of the module function, e.g. a ModuleInstance. """ - - funcrec = inspect.stack()[3] + stack = inspect.stack() + funcrec = stack[3] name = funcrec[3] frame = funcrec[0] symdict = dict(frame.f_globals) symdict.update(frame.f_locals) modctxt = False - callerrec = inspect.stack()[4] + callerrec = stack[4] f_locals = callerrec[0].f_locals if 'self' in f_locals: modctxt = isinstance(f_locals['self'], _ModuleInstance) @@ -85,6 +85,17 @@ class _Module(object): self.count += 1 return modinst + # This is the way to make the module decorator work on methods + # Turn it into a descriptor, used when accessed as an attribute + # In that case, the object is bound to the call method + # like done automatically for classic bound methods + # http://stackoverflow.com/a/3296318/574895 + def __get__(self, obj, objtype): + """Support instance methods.""" + import functools + return functools.partial(self.__call__, obj) + + class _ModuleInstance(object): def __init__(self, mod, *args, **kwargs): @@ -102,7 +113,6 @@ class _ModuleInstance(object): self.subs = _flatten(mod.modfunc(*args, **kwargs)) self.verify() self.update() - # self.inferInterface(*args, **kwargs) self.name = self.__name__ = mod.__name__ + '_' + str(mod.count) self.verilog_code = self.vhdl_code = None if hasattr(mod, 'verilog_code'): diff --git a/myhdl/test/conversion/general/test_method.py b/myhdl/test/conversion/general/test_method.py index bf7a5257..f0730855 100644 --- a/myhdl/test/conversion/general/test_method.py +++ b/myhdl/test/conversion/general/test_method.py @@ -7,6 +7,7 @@ class HdlObj(object): def __init__(self): pass + @module def method_func(self, clk, srst, x, y): z = Signal(intbv(0, min=y.min, max=y.max)) ifx = self._mfunc(x, z) @@ -19,12 +20,14 @@ class HdlObj(object): return hdl, ifx + @module def _mfunc(self, x, y): @always_comb def _hdl(): y.next = x + 1 return _hdl +@module def _func(x,y): @always_comb def _hdl(): @@ -35,6 +38,7 @@ class HdlObjObj(object): def __init__(self): pass + @module def method_func(self, clk, srst, x, y): z1 = Signal(intbv(0, min=y.min, max=y.max)) z2 = Signal(intbv(0, min=y.min, max=y.max)) @@ -55,6 +59,7 @@ class HdlObjAttrSimple(object): def __init__(self): self.AConstant = 3 + @module def method_func(self, clk, srst, x, y): # limitation for class method conversion, the object attributes @@ -78,6 +83,7 @@ class HdlObjAttr(object): self.z = Signal(intbv(0, min=y.min, max=y.max)) self.hobj = HdlObj() + @module def method_func(self): ifx = self.hobj._mfunc(self.x, self.z) @always(self.clk.posedge) @@ -89,6 +95,7 @@ class HdlObjAttr(object): return hdl, ifx +@module def ObjBench(hObj): clk = Signal(False) @@ -145,13 +152,13 @@ def ObjBench(hObj): def test_hdlobj(): - assert verify(ObjBench, HdlObj) == 0 + assert verify(ObjBench(HdlObj)) == 0 def test_hdlobjobj(): - assert verify(ObjBench, HdlObjObj) == 0 + assert verify(ObjBench(HdlObjObj)) == 0 def test_hdlobjattrsimple(): - assert verify(ObjBench, HdlObjAttrSimple) == 0 + assert verify(ObjBench(HdlObjAttrSimple)) == 0 #def test_hdlobjattr(): # # object attributes currently not supported, these