5a169ac430db4c87362d251735cd8223f4b87b3e
[nmigen.git] / nmigen / test / test_lib_cdc.py
1 # nmigen: UnusedElaboratable=no
2
3 from .utils import *
4 from ..hdl import *
5 from ..back.pysim import *
6 from ..lib.cdc import *
7
8
9 class FFSynchronizerTestCase(FHDLTestCase):
10 def test_stages_wrong(self):
11 with self.assertRaisesRegex(TypeError,
12 r"^Synchronization stage count must be a positive integer, not 0$"):
13 FFSynchronizer(Signal(), Signal(), stages=0)
14 with self.assertRaisesRegex(ValueError,
15 r"^Synchronization stage count may not safely be less than 2$"):
16 FFSynchronizer(Signal(), Signal(), stages=1)
17
18 def test_basic(self):
19 i = Signal()
20 o = Signal()
21 frag = FFSynchronizer(i, o)
22
23 sim = Simulator(frag)
24 sim.add_clock(1e-6)
25 def process():
26 self.assertEqual((yield o), 0)
27 yield i.eq(1)
28 yield Tick()
29 self.assertEqual((yield o), 0)
30 yield Tick()
31 self.assertEqual((yield o), 0)
32 yield Tick()
33 self.assertEqual((yield o), 1)
34 sim.add_process(process)
35 sim.run()
36
37 def test_reset_value(self):
38 i = Signal(reset=1)
39 o = Signal()
40 frag = FFSynchronizer(i, o, reset=1)
41
42 sim = Simulator(frag)
43 sim.add_clock(1e-6)
44 def process():
45 self.assertEqual((yield o), 1)
46 yield i.eq(0)
47 yield Tick()
48 self.assertEqual((yield o), 1)
49 yield Tick()
50 self.assertEqual((yield o), 1)
51 yield Tick()
52 self.assertEqual((yield o), 0)
53 sim.add_process(process)
54 sim.run()
55
56
57 class AsyncFFSynchronizerTestCase(FHDLTestCase):
58 def test_stages_wrong(self):
59 with self.assertRaisesRegex(TypeError,
60 r"^Synchronization stage count must be a positive integer, not 0$"):
61 ResetSynchronizer(Signal(), stages=0)
62 with self.assertRaisesRegex(ValueError,
63 r"^Synchronization stage count may not safely be less than 2$"):
64 ResetSynchronizer(Signal(), stages=1)
65
66 def test_edge_wrong(self):
67 with self.assertRaisesRegex(ValueError,
68 r"^AsyncFFSynchronizer async edge must be one of 'pos' or 'neg', not 'xxx'$"):
69 AsyncFFSynchronizer(Signal(), Signal(), domain="sync", async_edge="xxx")
70
71 def test_pos_edge(self):
72 i = Signal()
73 o = Signal()
74 m = Module()
75 m.domains += ClockDomain("sync")
76 m.submodules += AsyncFFSynchronizer(i, o)
77
78 sim = Simulator(m)
79 sim.add_clock(1e-6)
80 def process():
81 # initial reset
82 self.assertEqual((yield i), 0)
83 self.assertEqual((yield o), 1)
84 yield Tick(); yield Delay(1e-8)
85 self.assertEqual((yield o), 1)
86 yield Tick(); yield Delay(1e-8)
87 self.assertEqual((yield o), 0)
88 yield Tick(); yield Delay(1e-8)
89 self.assertEqual((yield o), 0)
90 yield Tick(); yield Delay(1e-8)
91
92 yield i.eq(1)
93 yield Delay(1e-8)
94 self.assertEqual((yield o), 1)
95 yield Tick(); yield Delay(1e-8)
96 self.assertEqual((yield o), 1)
97 yield i.eq(0)
98 yield Tick(); yield Delay(1e-8)
99 self.assertEqual((yield o), 1)
100 yield Tick(); yield Delay(1e-8)
101 self.assertEqual((yield o), 0)
102 yield Tick(); yield Delay(1e-8)
103 self.assertEqual((yield o), 0)
104 yield Tick(); yield Delay(1e-8)
105 sim.add_process(process)
106 with sim.write_vcd("test.vcd"):
107 sim.run()
108
109 def test_neg_edge(self):
110 i = Signal(reset=1)
111 o = Signal()
112 m = Module()
113 m.domains += ClockDomain("sync")
114 m.submodules += AsyncFFSynchronizer(i, o, async_edge="neg")
115
116 sim = Simulator(m)
117 sim.add_clock(1e-6)
118 def process():
119 # initial reset
120 self.assertEqual((yield i), 1)
121 self.assertEqual((yield o), 1)
122 yield Tick(); yield Delay(1e-8)
123 self.assertEqual((yield o), 1)
124 yield Tick(); yield Delay(1e-8)
125 self.assertEqual((yield o), 0)
126 yield Tick(); yield Delay(1e-8)
127 self.assertEqual((yield o), 0)
128 yield Tick(); yield Delay(1e-8)
129
130 yield i.eq(0)
131 yield Delay(1e-8)
132 self.assertEqual((yield o), 1)
133 yield Tick(); yield Delay(1e-8)
134 self.assertEqual((yield o), 1)
135 yield i.eq(1)
136 yield Tick(); yield Delay(1e-8)
137 self.assertEqual((yield o), 1)
138 yield Tick(); yield Delay(1e-8)
139 self.assertEqual((yield o), 0)
140 yield Tick(); yield Delay(1e-8)
141 self.assertEqual((yield o), 0)
142 yield Tick(); yield Delay(1e-8)
143 sim.add_process(process)
144 with sim.write_vcd("test.vcd"):
145 sim.run()
146
147
148 class ResetSynchronizerTestCase(FHDLTestCase):
149 def test_stages_wrong(self):
150 with self.assertRaisesRegex(TypeError,
151 r"^Synchronization stage count must be a positive integer, not 0$"):
152 ResetSynchronizer(Signal(), stages=0)
153 with self.assertRaisesRegex(ValueError,
154 r"^Synchronization stage count may not safely be less than 2$"):
155 ResetSynchronizer(Signal(), stages=1)
156
157 def test_basic(self):
158 arst = Signal()
159 m = Module()
160 m.domains += ClockDomain("sync")
161 m.submodules += ResetSynchronizer(arst)
162 s = Signal(reset=1)
163 m.d.sync += s.eq(0)
164
165 sim = Simulator(m)
166 sim.add_clock(1e-6)
167 def process():
168 # initial reset
169 self.assertEqual((yield s), 1)
170 yield Tick(); yield Delay(1e-8)
171 self.assertEqual((yield s), 1)
172 yield Tick(); yield Delay(1e-8)
173 self.assertEqual((yield s), 1)
174 yield Tick(); yield Delay(1e-8)
175 self.assertEqual((yield s), 0)
176 yield Tick(); yield Delay(1e-8)
177
178 yield arst.eq(1)
179 yield Delay(1e-8)
180 self.assertEqual((yield s), 0)
181 yield Tick(); yield Delay(1e-8)
182 self.assertEqual((yield s), 1)
183 yield arst.eq(0)
184 yield Tick(); yield Delay(1e-8)
185 self.assertEqual((yield s), 1)
186 yield Tick(); yield Delay(1e-8)
187 self.assertEqual((yield s), 1)
188 yield Tick(); yield Delay(1e-8)
189 self.assertEqual((yield s), 0)
190 yield Tick(); yield Delay(1e-8)
191 sim.add_process(process)
192 with sim.write_vcd("test.vcd"):
193 sim.run()
194
195
196 # TODO: test with distinct clocks
197 class PulseSynchronizerTestCase(FHDLTestCase):
198 def test_stages_wrong(self):
199 with self.assertRaisesRegex(TypeError,
200 r"^Synchronization stage count must be a positive integer, not 0$"):
201 PulseSynchronizer("w", "r", stages=0)
202 with self.assertRaisesRegex(ValueError,
203 r"^Synchronization stage count may not safely be less than 2$"):
204 PulseSynchronizer("w", "r", stages=1)
205
206 def test_smoke(self):
207 m = Module()
208 m.domains += ClockDomain("sync")
209 ps = m.submodules.dut = PulseSynchronizer("sync", "sync")
210
211 sim = Simulator(m)
212 sim.add_clock(1e-6)
213 def process():
214 yield ps.i.eq(0)
215 # TODO: think about reset
216 for n in range(5):
217 yield Tick()
218 # Make sure no pulses are generated in quiescent state
219 for n in range(3):
220 yield Tick()
221 self.assertEqual((yield ps.o), 0)
222 # Check conservation of pulses
223 accum = 0
224 for n in range(10):
225 yield ps.i.eq(1 if n < 4 else 0)
226 yield Tick()
227 accum += yield ps.o
228 self.assertEqual(accum, 4)
229 sim.add_process(process)
230 sim.run()