From 9511ae8fe0dc0d6c44af8aed975e273f15689e70 Mon Sep 17 00:00:00 2001 From: whitequark Date: Mon, 23 Sep 2019 19:38:21 +0000 Subject: [PATCH] lib.cdc: add diagnostic checks for synchronization stage count. --- nmigen/lib/cdc.py | 14 +++++++++++++- nmigen/test/test_lib_cdc.py | 16 ++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/nmigen/lib/cdc.py b/nmigen/lib/cdc.py index c26b961..d21df79 100644 --- a/nmigen/lib/cdc.py +++ b/nmigen/lib/cdc.py @@ -7,6 +7,14 @@ __all__ = ["FFSynchronizer", "ResetSynchronizer"] __all__ += ["MultiReg"] +def _check_stages(stages): + if not isinstance(stages, int) or stages < 1: + raise TypeError("Synchronization stage count must be a positive integer, not '{!r}'" + .format(stages)) + if stages < 2: + raise ValueError("Synchronization stage count may not safely be less than 2") + + class FFSynchronizer(Elaboratable): """Resynchronise a signal to a different clock domain. @@ -53,7 +61,9 @@ class FFSynchronizer(Elaboratable): :class:`FFSynchronizer` is reset by the ``o_domain`` reset only. """ - def __init__(self, i, o, *, o_domain="sync", stages=2, reset=0, reset_less=True): + def __init__(self, i, o, *, o_domain="sync", reset=0, reset_less=True, stages=2): + _check_stages(stages) + self.i = i self.o = o @@ -108,6 +118,8 @@ class ResetSynchronizer(Elaboratable): :class:`ResetSynchronizer`, e.g. to instantiate library cells directly. """ def __init__(self, arst, *, domain="sync", stages=2): + _check_stages(stages) + self.arst = arst self._domain = domain diff --git a/nmigen/test/test_lib_cdc.py b/nmigen/test/test_lib_cdc.py index 0d4894b..1178508 100644 --- a/nmigen/test/test_lib_cdc.py +++ b/nmigen/test/test_lib_cdc.py @@ -5,6 +5,14 @@ from ..lib.cdc import * class FFSynchronizerTestCase(FHDLTestCase): + def test_stages_wrong(self): + with self.assertRaises(TypeError, + msg="Synchronization stage count must be a positive integer, not '0'"): + FFSynchronizer(Signal(), Signal(), stages=0) + with self.assertRaises(ValueError, + msg="Synchronization stage count may not safely be less than 2"): + FFSynchronizer(Signal(), Signal(), stages=1) + def test_basic(self): i = Signal() o = Signal() @@ -43,6 +51,14 @@ class FFSynchronizerTestCase(FHDLTestCase): class ResetSynchronizerTestCase(FHDLTestCase): + def test_stages_wrong(self): + with self.assertRaises(TypeError, + msg="Synchronization stage count must be a positive integer, not '0'"): + ResetSynchronizer(Signal(), stages=0) + with self.assertRaises(ValueError, + msg="Synchronization stage count may not safely be less than 2"): + ResetSynchronizer(Signal(), stages=1) + def test_basic(self): arst = Signal() m = Module() -- 2.30.2