hdl.ir: detect elaboratables that are created but not used.

Requres every elaboratable to inherit from Elaboratable, but still
accepts ones that do not, with a warning.

Fixes #3.
This commit is contained in:
whitequark 2019-04-21 08:52:57 +00:00
parent 85ae99c1b4
commit 44711b7d08
22 changed files with 79 additions and 45 deletions

View file

@ -9,7 +9,7 @@ from .ir import *
from .xfrm import *
__all__ = ["Module", "SyntaxError", "SyntaxWarning"]
__all__ = ["SyntaxError", "SyntaxWarning", "Module"]
class SyntaxError(Exception):
@ -109,7 +109,7 @@ class FSM:
return self.state == self.encoding[name]
class Module(_ModuleBuilderRoot):
class Module(_ModuleBuilderRoot, Elaboratable):
def __init__(self):
_ModuleBuilderRoot.__init__(self, self, depth=0)
self.submodules = _ModuleBuilderSubmodules(self)

View file

@ -1,12 +1,30 @@
import warnings
from abc import ABCMeta, abstractmethod
from collections import defaultdict, OrderedDict
import warnings
import traceback
import sys
from ..tools import *
from .ast import *
from .cd import *
__all__ = ["Fragment", "Instance", "DriverConflict"]
__all__ = ["Elaboratable", "DriverConflict", "Fragment", "Instance"]
class Elaboratable(metaclass=ABCMeta):
def __new__(cls, *args, **kwargs):
self = super().__new__(cls)
self._Elaboratable__traceback = traceback.extract_stack()[:-1]
self._Elaboratable__used = False
return self
def __del__(self):
if hasattr(self, "_Elaboratable__used") and not self._Elaboratable__used:
print("Elaboratable created but never used\n",
"Traceback (most recent call last):\n",
*traceback.format_list(self._Elaboratable__traceback),
file=sys.stderr, sep="")
class DriverConflict(UserWarning):
@ -16,13 +34,22 @@ class DriverConflict(UserWarning):
class Fragment:
@staticmethod
def get(obj, platform):
if isinstance(obj, Fragment):
return obj
elif hasattr(obj, "elaborate"):
frag = obj.elaborate(platform)
else:
raise AttributeError("Object '{!r}' cannot be elaborated".format(obj))
return Fragment.get(frag, platform)
while True:
if isinstance(obj, Fragment):
return obj
elif isinstance(obj, Elaboratable):
obj._Elaboratable__used = True
obj = obj.elaborate(platform)
elif hasattr(obj, "elaborate"):
warnings.warn(
message="Class {!r} is an elaboratable that does not explicitly inherit from "
"Elaboratable; doing so would improve diagnostics"
.format(type(obj)),
category=RuntimeWarning,
stacklevel=2)
obj = obj.elaborate(platform)
else:
raise AttributeError("Object '{!r}' cannot be elaborated".format(obj))
def __init__(self):
self.ports = SignalDict()

View file

@ -1,6 +1,6 @@
from .. import tracer
from .ast import *
from .ir import Instance
from .ir import Elaboratable, Instance
__all__ = ["Memory", "ReadPort", "WritePort", "DummyPort"]
@ -70,7 +70,7 @@ class Memory:
return self._array[index]
class ReadPort:
class ReadPort(Elaboratable):
def __init__(self, memory, domain, synchronous, transparent):
self.memory = memory
self.domain = domain
@ -135,7 +135,7 @@ class ReadPort:
return f
class WritePort:
class WritePort(Elaboratable):
def __init__(self, memory, domain, priority, granularity):
self.memory = memory
self.domain = domain

View file

@ -292,7 +292,7 @@ class FragmentTransformer:
raise AttributeError("Object '{!r}' cannot be elaborated".format(value))
class TransformedElaboratable:
class TransformedElaboratable(Elaboratable):
def __init__(self, elaboratable):
assert hasattr(elaboratable, "elaborate")