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: 664b4bcb3ac2
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: 011bf2258e77
Choose a head ref
  • 1 commit
  • 5 files changed
  • 1 contributor

Commits on Jan 14, 2019

  1. hdl: make ClockSignal and ResetSignal usable on LHS.

    Fixes #8.
    whitequark committed Jan 14, 2019
    Copy the full SHA
    011bf22 View commit details
Showing with 73 additions and 4 deletions.
  1. +19 −0 examples/por.py
  2. +20 −4 nmigen/hdl/ast.py
  3. +4 −0 nmigen/hdl/xfrm.py
  4. +18 −0 nmigen/test/test_hdl_dsl.py
  5. +12 −0 nmigen/test/test_hdl_xfrm.py
19 changes: 19 additions & 0 deletions examples/por.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
from nmigen import *
from nmigen.cli import main


m = Module()
cd_por = ClockDomain(reset_less=True)
cd_sync = ClockDomain()
m.domains += cd_por, cd_sync

delay = Signal(max=255, reset=255)
with m.If(delay != 0):
m.d.por += delay.eq(delay - 1)
m.d.comb += [
ClockSignal().eq(cd_por.clk),
ResetSignal().eq(delay == 0),
]

if __name__ == "__main__":
main(m.lower(platform=None), ports=[cd_por.clk])
24 changes: 20 additions & 4 deletions nmigen/hdl/ast.py
Original file line number Diff line number Diff line change
@@ -635,6 +635,9 @@ def __init__(self, domain="sync"):
def shape(self):
return 1, False

def _lhs_signals(self):
return ValueSet((self,))

def _rhs_signals(self):
raise NotImplementedError("ClockSignal must be lowered to a concrete signal") # :nocov:

@@ -666,6 +669,9 @@ def __init__(self, domain="sync", allow_reset_less=False):
def shape(self):
return 1, False

def _lhs_signals(self):
return ValueSet((self,))

def _rhs_signals(self):
raise NotImplementedError("ResetSignal must be lowered to a concrete signal") # :nocov:

@@ -1038,6 +1044,8 @@ def __hash__(self):
return hash(self.value.value)
elif isinstance(self.value, Signal):
return hash(self.value.duid)
elif isinstance(self.value, (ClockSignal, ResetSignal)):
return hash(self.value.domain)
elif isinstance(self.value, Operator):
return hash((self.value.op, tuple(ValueKey(o) for o in self.value.operands)))
elif isinstance(self.value, Slice):
@@ -1064,6 +1072,8 @@ def __eq__(self, other):
return self.value.value == other.value.value
elif isinstance(self.value, Signal):
return self.value is other.value
elif isinstance(self.value, (ClockSignal, ResetSignal)):
return self.value.domain == other.value.domain
elif isinstance(self.value, Operator):
return (self.value.op == other.value.op and
len(self.value.operands) == len(other.value.operands) and
@@ -1123,22 +1133,28 @@ class ValueSet(_MappedKeySet):

class SignalKey:
def __init__(self, signal):
if type(signal) is not Signal:
if type(signal) is Signal:
self._intern = (0, signal.duid)
elif type(signal) is ClockSignal:
self._intern = (1, signal.domain)
elif type(signal) is ResetSignal:
self._intern = (2, signal.domain)
else:
raise TypeError("Object '{!r}' is not an nMigen signal".format(signal))
self.signal = signal

def __hash__(self):
return hash(self.signal.duid)
return hash(self._intern)

def __eq__(self, other):
if type(other) is not SignalKey:
return False
return self.signal is other.signal
return self._intern == other._intern

def __lt__(self, other):
if type(other) is not SignalKey:
raise TypeError("Object '{!r}' cannot be compared to a SignalKey".format(signal))
return self.signal.duid < other.signal.duid
return self._intern < other._intern

def __repr__(self):
return "<{}.SignalKey {!r}>".format(__name__, self.signal)
4 changes: 4 additions & 0 deletions nmigen/hdl/xfrm.py
Original file line number Diff line number Diff line change
@@ -293,6 +293,10 @@ def _resolve(self, domain, context):
.format(context, domain))
return self.domains[domain]

def map_drivers(self, fragment, new_fragment):
for domain, signal in fragment.iter_drivers():
new_fragment.add_driver(self.on_value(signal), domain)

def on_ClockSignal(self, value):
cd = self._resolve(value.domain, value)
return cd.clk
18 changes: 18 additions & 0 deletions nmigen/test/test_hdl_dsl.py
Original file line number Diff line number Diff line change
@@ -95,6 +95,24 @@ def test_attr_wrong(self):
msg="'Module' object has no attribute 'nonexistentattr'"):
m.nonexistentattr

def test_clock_signal(self):
m = Module()
m.d.comb += ClockSignal("pix").eq(ClockSignal())
self.assertRepr(m._statements, """
(
(eq (clk pix) (clk sync))
)
""")

def test_reset_signal(self):
m = Module()
m.d.comb += ResetSignal("pix").eq(1)
self.assertRepr(m._statements, """
(
(eq (rst pix) (const 1'd1))
)
""")

def test_If(self):
m = Module()
with m.If(self.s1):
12 changes: 12 additions & 0 deletions nmigen/test/test_hdl_xfrm.py
Original file line number Diff line number Diff line change
@@ -135,6 +135,18 @@ def test_lower_rst_reset_less(self):
)
""")

def test_lower_drivers(self):
pix = ClockDomain()
f = Fragment()
f.add_driver(ClockSignal("pix"), None)
f.add_driver(ResetSignal("pix"), "sync")

f = DomainLowerer({"pix": pix})(f)
self.assertEqual(f.drivers, {
None: SignalSet((pix.clk,)),
"sync": SignalSet((pix.rst,))
})

def test_lower_wrong_domain(self):
sync = ClockDomain()
f = Fragment()