Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: m-labs/nmigen
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 958cb18b886a
Choose a base ref
...
head repository: m-labs/nmigen
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 3e58202e7024
Choose a head ref
  • 1 commit
  • 3 files changed
  • 1 contributor

Commits on May 12, 2019

  1. hdl: make all public Value classes other than Record final.

    In some cases, nMigen uses type() instead of isinstance() to dispatch
    on types. Make sure all such uses of type() are robust; in addition,
    make it clear that nMigen AST classes are not meant to be subclassed.
    (Record is an exception.)
    
    Fixes #65.
    whitequark committed May 12, 2019
    Copy the full SHA
    3e58202 View commit details
Showing with 30 additions and 1 deletion.
  1. +20 −0 nmigen/hdl/ast.py
  2. +1 −0 nmigen/hdl/rec.py
  3. +9 −1 nmigen/tools.py
20 changes: 20 additions & 0 deletions nmigen/hdl/ast.py
Original file line number Diff line number Diff line change
@@ -210,6 +210,7 @@ def _as_const(self):
__hash__ = None


@final
class Const(Value):
"""A constant, literal integer value.
@@ -283,16 +284,19 @@ def _rhs_signals(self):
return ValueSet()


@final
class AnyConst(AnyValue):
def __repr__(self):
return "(anyconst {}'{})".format(self.nbits, "s" if self.signed else "")


@final
class AnySeq(AnyValue):
def __repr__(self):
return "(anyseq {}'{})".format(self.nbits, "s" if self.signed else "")


@final
class Operator(Value):
def __init__(self, op, operands, src_loc_at=0):
super().__init__(src_loc_at=1 + src_loc_at)
@@ -387,6 +391,7 @@ def Mux(sel, val1, val0):
return Operator("m", [sel, val1, val0], src_loc_at=1)


@final
class Slice(Value):
def __init__(self, value, start, end):
if not isinstance(start, int):
@@ -424,6 +429,7 @@ def __repr__(self):
return "(slice {} {}:{})".format(repr(self.value), self.start, self.end)


@final
class Part(Value):
def __init__(self, value, offset, width):
if not isinstance(width, int) or width < 0:
@@ -447,6 +453,7 @@ def __repr__(self):
return "(part {} {} {})".format(repr(self.value), repr(self.offset), self.width)


@final
class Cat(Value):
"""Concatenate values.
@@ -495,6 +502,7 @@ def __repr__(self):
return "(cat {})".format(" ".join(map(repr, self.parts)))


@final
class Repl(Value):
"""Replicate a value
@@ -534,6 +542,7 @@ def __repr__(self):
return "(repl {!r} {})".format(self.value, self.count)


@final
class Signal(Value, DUID):
"""A varying integer value.
@@ -649,6 +658,7 @@ def __repr__(self):
return "(sig {})".format(self.name)


@final
class ClockSignal(Value):
"""Clock signal for a clock domain.
@@ -680,6 +690,7 @@ def __repr__(self):
return "(clk {})".format(self.domain)


@final
class ResetSignal(Value):
"""Reset signal for a clock domain.
@@ -802,6 +813,7 @@ def __repr__(self):
", ".join(map(repr, self._inner)))


@final
class ArrayProxy(Value):
def __init__(self, elems, index):
super().__init__(src_loc_at=1)
@@ -836,6 +848,7 @@ def __repr__(self):
return "(proxy (array [{}]) {!r})".format(", ".join(map(repr, self.elems)), self.index)


@final
class Sample(Value):
"""Value from the past.
@@ -899,6 +912,7 @@ def wrap(obj):
raise TypeError("Object '{!r}' is not an nMigen statement".format(obj))


@final
class Assign(Statement):
def __init__(self, lhs, rhs):
self.lhs = Value.wrap(lhs)
@@ -940,14 +954,17 @@ def __repr__(self):
return "({} {!r})".format(self._kind, self.test)


@final
class Assert(Property):
_kind = "assert"


@final
class Assume(Property):
_kind = "assume"


@final
class Switch(Statement):
def __init__(self, test, cases):
self.test = Value.wrap(test)
@@ -981,6 +998,7 @@ def __repr__(self):
return "(switch {!r} {})".format(self.test, " ".join(cases))


@final
class Delay(Statement):
def __init__(self, interval=None):
self.interval = None if interval is None else float(interval)
@@ -995,6 +1013,7 @@ def __repr__(self):
return "(delay {:.3}us)".format(self.interval * 1e6)


@final
class Tick(Statement):
def __init__(self, domain="sync"):
self.domain = str(domain)
@@ -1006,6 +1025,7 @@ def __repr__(self):
return "(tick {})".format(self.domain)


@final
class Passive(Statement):
def _rhs_signals(self):
return ValueSet()
1 change: 1 addition & 0 deletions nmigen/hdl/rec.py
Original file line number Diff line number Diff line change
@@ -62,6 +62,7 @@ def __iter__(self):
yield (name, shape, dir)


# Unlike most Values, Record *can* be subclassed.
class Record(Value):
def __init__(self, layout, name=None):
if name is None:
10 changes: 9 additions & 1 deletion nmigen/tools.py
Original file line number Diff line number Diff line change
@@ -6,7 +6,7 @@
from contextlib import contextmanager


__all__ = ["flatten", "union", "log2_int", "bits_for", "memoize", "deprecated"]
__all__ = ["flatten", "union", "log2_int", "bits_for", "memoize", "final", "deprecated"]


def flatten(i):
@@ -57,6 +57,14 @@ def g(*args):
return g


def final(cls):
def init_subclass():
raise TypeError("Subclassing {}.{} is not supported"
.format(cls.__module__, cls.__name__))
cls.__init_subclass__ = init_subclass
return cls


def deprecated(message, stacklevel=2):
def decorator(f):
@functools.wraps(f)