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