Skip to content

Commit a27c13e

Browse files
committed
lib.cdc: Add docstrings and basic parameter checking to MultiReg and ResetSynchroniser.
1 parent 4027317 commit a27c13e

File tree

2 files changed

+81
-0
lines changed

2 files changed

+81
-0
lines changed

nmigen/lib/cdc.py

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,40 @@
55

66

77
class MultiReg:
8+
"""Resynchronise a signal to a different clock domain.
9+
10+
Consists of a chain of flipflops. Eliminates metastabilities
11+
at the output, but does not provide any other guarantees as
12+
to the safe domain-crossing of a signal.
13+
14+
Parameters
15+
----------
16+
i : Signal(), in
17+
Signal to be resynchronised
18+
o : Signal(), out
19+
Signal connected to synchroniser output
20+
odomain : str
21+
Name of output clock domain
22+
n : int
23+
Number of flops between input and output.
24+
To avoid exposing output domain to metastabilities,
25+
n should be >= 2.
26+
reset : int
27+
Reset value of the flipflops.
28+
TODO: but it's reset_less???
29+
30+
Override
31+
--------
32+
Define the `get_multi_reg` platform attribute to override
33+
the implementation of MultiReg, e.g. to instantiate
34+
library cells directly.
35+
"""
836
def __init__(self, i, o, odomain="sync", n=2, reset=0):
37+
if not isinstance(n, int) or n < 1:
38+
raise TypeError("n must be a positive integer, not '{!r}'".format(n))
39+
if not isinstance(reset, int):
40+
raise TypeError("reset must be a constant integer, not '{!r}'".format(n))
41+
942
self.i = i
1043
self.o = o
1144
self.odomain = odomain
@@ -26,7 +59,33 @@ def elaborate(self, platform):
2659

2760

2861
class ResetSynchronizer:
62+
"""Synchronise the deassertion of a reset to a local clock.
63+
64+
The reset may still be asserted asynchronously. This module
65+
assists with guaranteeing a minimum pulse width, and
66+
meeting removal/recovery constraints.
67+
68+
Parameters
69+
----------
70+
arst : Signal(1), out
71+
Resynchronised reset signal.
72+
Asserted when this module is reset,
73+
deasserted after n clocks.
74+
domain : str
75+
Name of domain to synchronise reset to
76+
n : int, >=1
77+
Number of clock edges from input deassertion
78+
to output deassertion
79+
80+
Override
81+
--------
82+
Define the `get_reset_sync` platform attribute to override
83+
the implementation of ResetSynchronizer, e.g. to instantiate
84+
library cells directly.
85+
"""
2986
def __init__(self, arst, domain="sync", n=2):
87+
if not isinstance(n, int) or n < 1:
88+
raise TypeError("n must be a positive integer, not '{!r}'".format(n))
3089
self.arst = arst
3190
self.domain = domain
3291

nmigen/test/test_lib_cdc.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,20 @@
77

88

99
class MultiRegTestCase(FHDLTestCase):
10+
def test_paramcheck(self):
11+
i = Signal()
12+
o = Signal()
13+
with self.assertRaises(TypeError):
14+
m = MultiReg(i, o, n=0)
15+
with self.assertRaises(TypeError):
16+
m = MultiReg(i, o, n="x")
17+
with self.assertRaises(TypeError):
18+
m = MultiReg(i, o, n=2, reset="a")
19+
with self.assertRaises(TypeError):
20+
m = MultiReg(i, o, n=2, reset=i)
21+
m = MultiReg(i, o, n=1)
22+
m = MultiReg(i, o, reset=-1)
23+
1024
def test_basic(self):
1125
i = Signal()
1226
o = Signal()
@@ -45,6 +59,14 @@ def process():
4559

4660

4761
class ResetSynchronizerTestCase(FHDLTestCase):
62+
def test_paramcheck(self):
63+
arst = Signal()
64+
with self.assertRaises(TypeError):
65+
r = ResetSynchronizer(arst, n=0)
66+
with self.assertRaises(TypeError):
67+
r = ResetSynchronizer(arst, n="a")
68+
r = ResetSynchronizer(arst)
69+
4870
def test_basic(self):
4971
arst = Signal()
5072
m = Module()

0 commit comments

Comments
 (0)