lib.cdc: extract AsyncFFSynchronizer.
In some cases, it is necessary to synchronize a reset-like signal but a new clock domain is not desirable. To address these cases, extract the implementation of ResetSynchronizer into AsyncFFSynchronizer, and replace ResetSynchronizer with a thin wrapper around it.
This commit is contained in:
parent
a14a5723c1
commit
2f8669cad6
7 changed files with 229 additions and 60 deletions
|
|
@ -54,6 +54,97 @@ class FFSynchronizerTestCase(FHDLTestCase):
|
|||
sim.run()
|
||||
|
||||
|
||||
class AsyncFFSynchronizerTestCase(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_edge_wrong(self):
|
||||
with self.assertRaises(ValueError,
|
||||
msg="AsyncFFSynchronizer async edge must be one of 'pos' or 'neg', not 'xxx'"):
|
||||
AsyncFFSynchronizer(Signal(), Signal(), domain="sync", async_edge="xxx")
|
||||
|
||||
def test_pos_edge(self):
|
||||
i = Signal()
|
||||
o = Signal()
|
||||
m = Module()
|
||||
m.domains += ClockDomain("sync")
|
||||
m.submodules += AsyncFFSynchronizer(i, o)
|
||||
|
||||
sim = Simulator(m)
|
||||
sim.add_clock(1e-6)
|
||||
def process():
|
||||
# initial reset
|
||||
self.assertEqual((yield i), 0)
|
||||
self.assertEqual((yield o), 1)
|
||||
yield Tick(); yield Delay(1e-8)
|
||||
self.assertEqual((yield o), 1)
|
||||
yield Tick(); yield Delay(1e-8)
|
||||
self.assertEqual((yield o), 0)
|
||||
yield Tick(); yield Delay(1e-8)
|
||||
self.assertEqual((yield o), 0)
|
||||
yield Tick(); yield Delay(1e-8)
|
||||
|
||||
yield i.eq(1)
|
||||
yield Delay(1e-8)
|
||||
self.assertEqual((yield o), 1)
|
||||
yield Tick(); yield Delay(1e-8)
|
||||
self.assertEqual((yield o), 1)
|
||||
yield i.eq(0)
|
||||
yield Tick(); yield Delay(1e-8)
|
||||
self.assertEqual((yield o), 1)
|
||||
yield Tick(); yield Delay(1e-8)
|
||||
self.assertEqual((yield o), 0)
|
||||
yield Tick(); yield Delay(1e-8)
|
||||
self.assertEqual((yield o), 0)
|
||||
yield Tick(); yield Delay(1e-8)
|
||||
sim.add_process(process)
|
||||
with sim.write_vcd("test.vcd"):
|
||||
sim.run()
|
||||
|
||||
def test_neg_edge(self):
|
||||
i = Signal(reset=1)
|
||||
o = Signal()
|
||||
m = Module()
|
||||
m.domains += ClockDomain("sync")
|
||||
m.submodules += AsyncFFSynchronizer(i, o, async_edge="neg")
|
||||
|
||||
sim = Simulator(m)
|
||||
sim.add_clock(1e-6)
|
||||
def process():
|
||||
# initial reset
|
||||
self.assertEqual((yield i), 1)
|
||||
self.assertEqual((yield o), 1)
|
||||
yield Tick(); yield Delay(1e-8)
|
||||
self.assertEqual((yield o), 1)
|
||||
yield Tick(); yield Delay(1e-8)
|
||||
self.assertEqual((yield o), 0)
|
||||
yield Tick(); yield Delay(1e-8)
|
||||
self.assertEqual((yield o), 0)
|
||||
yield Tick(); yield Delay(1e-8)
|
||||
|
||||
yield i.eq(0)
|
||||
yield Delay(1e-8)
|
||||
self.assertEqual((yield o), 1)
|
||||
yield Tick(); yield Delay(1e-8)
|
||||
self.assertEqual((yield o), 1)
|
||||
yield i.eq(1)
|
||||
yield Tick(); yield Delay(1e-8)
|
||||
self.assertEqual((yield o), 1)
|
||||
yield Tick(); yield Delay(1e-8)
|
||||
self.assertEqual((yield o), 0)
|
||||
yield Tick(); yield Delay(1e-8)
|
||||
self.assertEqual((yield o), 0)
|
||||
yield Tick(); yield Delay(1e-8)
|
||||
sim.add_process(process)
|
||||
with sim.write_vcd("test.vcd"):
|
||||
sim.run()
|
||||
|
||||
|
||||
class ResetSynchronizerTestCase(FHDLTestCase):
|
||||
def test_stages_wrong(self):
|
||||
with self.assertRaises(TypeError,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue