sim: split into base, core, and engines.
[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_pos_edge(self):
73 i = Signal()
74 o = Signal()
75 m = Module()
76 m.domains += ClockDomain("sync")
77 m.submodules += AsyncFFSynchronizer(i, o)
78
79 sim = Simulator(m)
80 sim.add_clock(1e-6)
81 def process():
82 # initial reset
83 self.assertEqual((yield i), 0)
84 self.assertEqual((yield o), 1)
85 yield Tick(); yield Delay(1e-8)
86 self.assertEqual((yield o), 1)
87 yield Tick(); yield Delay(1e-8)
88 self.assertEqual((yield o), 0)
89 yield Tick(); yield Delay(1e-8)
90 self.assertEqual((yield o), 0)
91 yield Tick(); yield Delay(1e-8)
92
93 yield i.eq(1)
94 yield Delay(1e-8)
95 self.assertEqual((yield o), 1)
96 yield Tick(); yield Delay(1e-8)
97 self.assertEqual((yield o), 1)
98 yield i.eq(0)
99 yield Tick(); yield Delay(1e-8)
100 self.assertEqual((yield o), 1)
101 yield Tick(); yield Delay(1e-8)
102 self.assertEqual((yield o), 0)
103 yield Tick(); yield Delay(1e-8)
104 self.assertEqual((yield o), 0)
105 yield Tick(); yield Delay(1e-8)
106 sim.add_process(process)
107 with sim.write_vcd("test.vcd"):
108 sim.run()
109
110 def test_neg_edge(self):
111 i = Signal(reset=1)
112 o = Signal()
113 m = Module()
114 m.domains += ClockDomain("sync")
115 m.submodules += AsyncFFSynchronizer(i, o, async_edge="neg")
116
117 sim = Simulator(m)
118 sim.add_clock(1e-6)
119 def process():
120 # initial reset
121 self.assertEqual((yield i), 1)
122 self.assertEqual((yield o), 1)
123 yield Tick(); yield Delay(1e-8)
124 self.assertEqual((yield o), 1)
125 yield Tick(); yield Delay(1e-8)
126 self.assertEqual((yield o), 0)
127 yield Tick(); yield Delay(1e-8)
128 self.assertEqual((yield o), 0)
129 yield Tick(); yield Delay(1e-8)
130
131 yield i.eq(0)
132 yield Delay(1e-8)
133 self.assertEqual((yield o), 1)
134 yield Tick(); yield Delay(1e-8)
135 self.assertEqual((yield o), 1)
136 yield i.eq(1)
137 yield Tick(); yield Delay(1e-8)
138 self.assertEqual((yield o), 1)
139 yield Tick(); yield Delay(1e-8)
140 self.assertEqual((yield o), 0)
141 yield Tick(); yield Delay(1e-8)
142 self.assertEqual((yield o), 0)
143 yield Tick(); yield Delay(1e-8)
144 sim.add_process(process)
145 with sim.write_vcd("test.vcd"):
146 sim.run()
147
148
149 class ResetSynchronizerTestCase(FHDLTestCase):
150 def test_stages_wrong(self):
151 with self.assertRaisesRegex(TypeError,
152 r"^Synchronization stage count must be a positive integer, not 0$"):
153 ResetSynchronizer(Signal(), stages=0)
154 with self.assertRaisesRegex(ValueError,
155 r"^Synchronization stage count may not safely be less than 2$"):
156 ResetSynchronizer(Signal(), stages=1)
157
158 def test_basic(self):
159 arst = Signal()
160 m = Module()
161 m.domains += ClockDomain("sync")
162 m.submodules += ResetSynchronizer(arst)
163 s = Signal(reset=1)
164 m.d.sync += s.eq(0)
165
166 sim = Simulator(m)
167 sim.add_clock(1e-6)
168 def process():
169 # initial reset
170 self.assertEqual((yield s), 1)
171 yield Tick(); yield Delay(1e-8)
172 self.assertEqual((yield s), 1)
173 yield Tick(); yield Delay(1e-8)
174 self.assertEqual((yield s), 1)
175 yield Tick(); yield Delay(1e-8)
176 self.assertEqual((yield s), 0)
177 yield Tick(); yield Delay(1e-8)
178
179 yield arst.eq(1)
180 yield Delay(1e-8)
181 self.assertEqual((yield s), 0)
182 yield Tick(); yield Delay(1e-8)
183 self.assertEqual((yield s), 1)
184 yield arst.eq(0)
185 yield Tick(); yield Delay(1e-8)
186 self.assertEqual((yield s), 1)
187 yield Tick(); yield Delay(1e-8)
188 self.assertEqual((yield s), 1)
189 yield Tick(); yield Delay(1e-8)
190 self.assertEqual((yield s), 0)
191 yield Tick(); yield Delay(1e-8)
192 sim.add_process(process)
193 with sim.write_vcd("test.vcd"):
194 sim.run()
195
196
197 # TODO: test with distinct clocks
198 class PulseSynchronizerTestCase(FHDLTestCase):
199 def test_stages_wrong(self):
200 with self.assertRaisesRegex(TypeError,
201 r"^Synchronization stage count must be a positive integer, not 0$"):
202 PulseSynchronizer("w", "r", stages=0)
203 with self.assertRaisesRegex(ValueError,
204 r"^Synchronization stage count may not safely be less than 2$"):
205 PulseSynchronizer("w", "r", stages=1)
206
207 def test_smoke(self):
208 m = Module()
209 m.domains += ClockDomain("sync")
210 ps = m.submodules.dut = PulseSynchronizer("sync", "sync")
211
212 sim = Simulator(m)
213 sim.add_clock(1e-6)
214 def process():
215 yield ps.i.eq(0)
216 # TODO: think about reset
217 for n in range(5):
218 yield Tick()
219 # Make sure no pulses are generated in quiescent state
220 for n in range(3):
221 yield Tick()
222 self.assertEqual((yield ps.o), 0)
223 # Check conservation of pulses
224 accum = 0
225 for n in range(10):
226 yield ps.i.eq(1 if n < 4 else 0)
227 yield Tick()
228 accum += yield ps.o
229 self.assertEqual(accum, 4)
230 sim.add_process(process)
231 sim.run()