csr.bus.Multiplexer: fix element w_stb getting stuck.
[nmigen-soc.git] / nmigen_soc / test / test_csr_bus.py
1 import unittest
2 from nmigen import *
3 from nmigen.hdl.rec import Layout
4 from nmigen.back.pysim import *
5
6 from ..csr.bus import *
7
8
9 class ElementTestCase(unittest.TestCase):
10 def test_layout_1_ro(self):
11 elem = Element(1, "r")
12 self.assertEqual(elem.width, 1)
13 self.assertEqual(elem.access, Element.Access.R)
14 self.assertEqual(elem.layout, Layout.cast([
15 ("r_data", 1),
16 ("r_stb", 1),
17 ]))
18
19 def test_layout_8_rw(self):
20 elem = Element(8, access="rw")
21 self.assertEqual(elem.width, 8)
22 self.assertEqual(elem.access, Element.Access.RW)
23 self.assertEqual(elem.layout, Layout.cast([
24 ("r_data", 8),
25 ("r_stb", 1),
26 ("w_data", 8),
27 ("w_stb", 1),
28 ]))
29
30 def test_layout_10_wo(self):
31 elem = Element(10, "w")
32 self.assertEqual(elem.width, 10)
33 self.assertEqual(elem.access, Element.Access.W)
34 self.assertEqual(elem.layout, Layout.cast([
35 ("w_data", 10),
36 ("w_stb", 1),
37 ]))
38
39 def test_layout_0_rw(self): # degenerate but legal case
40 elem = Element(0, access=Element.Access.RW)
41 self.assertEqual(elem.width, 0)
42 self.assertEqual(elem.access, Element.Access.RW)
43 self.assertEqual(elem.layout, Layout.cast([
44 ("r_data", 0),
45 ("r_stb", 1),
46 ("w_data", 0),
47 ("w_stb", 1),
48 ]))
49
50 def test_width_wrong(self):
51 with self.assertRaisesRegex(ValueError,
52 r"Width must be a non-negative integer, not -1"):
53 Element(-1, "rw")
54
55 def test_access_wrong(self):
56 with self.assertRaisesRegex(ValueError,
57 r"Access mode must be one of \"r\", \"w\", or \"rw\", not 'wo'"):
58 Element(1, "wo")
59
60
61 class InterfaceTestCase(unittest.TestCase):
62 def test_layout(self):
63 iface = Interface(addr_width=12, data_width=8)
64 self.assertEqual(iface.addr_width, 12)
65 self.assertEqual(iface.data_width, 8)
66 self.assertEqual(iface.layout, Layout.cast([
67 ("addr", 12),
68 ("r_data", 8),
69 ("r_stb", 1),
70 ("w_data", 8),
71 ("w_stb", 1),
72 ]))
73
74 def test_wrong_addr_width(self):
75 with self.assertRaisesRegex(ValueError,
76 r"Address width must be a positive integer, not -1"):
77 Interface(addr_width=-1, data_width=8)
78
79 def test_wrong_data_width(self):
80 with self.assertRaisesRegex(ValueError,
81 r"Data width must be a positive integer, not -1"):
82 Interface(addr_width=16, data_width=-1)
83
84
85 class MultiplexerTestCase(unittest.TestCase):
86 def setUp(self):
87 self.dut = Multiplexer(addr_width=16, data_width=8)
88 Fragment.get(self.dut, platform=None) # silence UnusedElaboratable
89
90 def test_add_4b(self):
91 self.assertEqual(self.dut.add(Element(4, "rw")),
92 (0, 1))
93
94 def test_add_8b(self):
95 self.assertEqual(self.dut.add(Element(8, "rw")),
96 (0, 1))
97
98 def test_add_12b(self):
99 self.assertEqual(self.dut.add(Element(12, "rw")),
100 (0, 2))
101
102 def test_add_16b(self):
103 self.assertEqual(self.dut.add(Element(16, "rw")),
104 (0, 2))
105
106 def test_add_two(self):
107 self.assertEqual(self.dut.add(Element(16, "rw")),
108 (0, 2))
109 self.assertEqual(self.dut.add(Element(8, "rw")),
110 (2, 3))
111
112 def test_add_wrong(self):
113 with self.assertRaisesRegex(ValueError,
114 r"Width must be a non-negative integer, not -1"):
115 Element(-1, "rw")
116
117 def test_align_to(self):
118 self.assertEqual(self.dut.add(Element(8, "rw")),
119 (0, 1))
120 self.assertEqual(self.dut.align_to(2), 4)
121 self.assertEqual(self.dut.add(Element(8, "rw")),
122 (4, 5))
123
124 def test_sim(self):
125 bus = self.dut.bus
126
127 elem_4_r = Element(4, "r")
128 self.dut.add(elem_4_r)
129 elem_8_w = Element(8, "w")
130 self.dut.add(elem_8_w)
131 elem_16_rw = Element(16, "rw")
132 self.dut.add(elem_16_rw)
133
134 def sim_test():
135 yield elem_4_r.r_data.eq(0xa)
136 yield elem_16_rw.r_data.eq(0x5aa5)
137
138 yield bus.addr.eq(0)
139 yield bus.r_stb.eq(1)
140 yield
141 yield bus.r_stb.eq(0)
142 self.assertEqual((yield elem_4_r.r_stb), 1)
143 self.assertEqual((yield elem_16_rw.r_stb), 0)
144 yield
145 self.assertEqual((yield bus.r_data), 0xa)
146
147 yield bus.addr.eq(2)
148 yield bus.r_stb.eq(1)
149 yield
150 yield bus.r_stb.eq(0)
151 self.assertEqual((yield elem_4_r.r_stb), 0)
152 self.assertEqual((yield elem_16_rw.r_stb), 1)
153 yield
154 yield bus.addr.eq(3) # pipeline a read
155 self.assertEqual((yield bus.r_data), 0xa5)
156
157 yield bus.r_stb.eq(1)
158 yield
159 yield bus.r_stb.eq(0)
160 self.assertEqual((yield elem_4_r.r_stb), 0)
161 self.assertEqual((yield elem_16_rw.r_stb), 0)
162 yield
163 self.assertEqual((yield bus.r_data), 0x5a)
164
165 yield bus.addr.eq(1)
166 yield bus.w_data.eq(0x3d)
167 yield bus.w_stb.eq(1)
168 yield
169 yield bus.w_stb.eq(0)
170 yield bus.addr.eq(2) # change address
171 yield
172 self.assertEqual((yield elem_8_w.w_stb), 1)
173 self.assertEqual((yield elem_8_w.w_data), 0x3d)
174 self.assertEqual((yield elem_16_rw.w_stb), 0)
175 yield
176 self.assertEqual((yield elem_8_w.w_stb), 0)
177
178 yield bus.addr.eq(2)
179 yield bus.w_data.eq(0x55)
180 yield bus.w_stb.eq(1)
181 yield
182 self.assertEqual((yield elem_8_w.w_stb), 0)
183 self.assertEqual((yield elem_16_rw.w_stb), 0)
184 yield bus.addr.eq(3) # pipeline a write
185 yield bus.w_data.eq(0xaa)
186 yield
187 self.assertEqual((yield elem_8_w.w_stb), 0)
188 self.assertEqual((yield elem_16_rw.w_stb), 0)
189 yield bus.w_stb.eq(0)
190 yield
191 self.assertEqual((yield elem_8_w.w_stb), 0)
192 self.assertEqual((yield elem_16_rw.w_stb), 1)
193 self.assertEqual((yield elem_16_rw.w_data), 0xaa55)
194
195 with Simulator(self.dut, vcd_file=open("test.vcd", "w")) as sim:
196 sim.add_clock(1e-6)
197 sim.add_sync_process(sim_test())
198 sim.run()
199
200
201 class MultiplexerAlignedTestCase(unittest.TestCase):
202 def setUp(self):
203 self.dut = Multiplexer(addr_width=16, data_width=8, alignment=2)
204 Fragment.get(self.dut, platform=None) # silence UnusedElaboratable
205
206 def test_add_two(self):
207 self.assertEqual(self.dut.add(Element(8, "rw")),
208 (0, 4))
209 self.assertEqual(self.dut.add(Element(16, "rw")),
210 (4, 8))
211
212 def test_over_align_to(self):
213 self.assertEqual(self.dut.add(Element(8, "rw")),
214 (0, 4))
215 self.assertEqual(self.dut.align_to(3), 8)
216 self.assertEqual(self.dut.add(Element(8, "rw")),
217 (8, 12))
218
219 def test_under_align_to(self):
220 self.assertEqual(self.dut.add(Element(8, "rw")),
221 (0, 4))
222 self.assertEqual(self.dut.align_to(1), 4)
223 self.assertEqual(self.dut.add(Element(8, "rw")),
224 (4, 8))
225
226 def test_sim(self):
227 bus = self.dut.bus
228
229 elem_20_rw = Element(20, "rw")
230 self.dut.add(elem_20_rw)
231
232 def sim_test():
233 yield bus.w_stb.eq(1)
234 yield bus.addr.eq(0)
235 yield bus.w_data.eq(0x55)
236 yield
237 self.assertEqual((yield elem_20_rw.w_stb), 0)
238 yield bus.addr.eq(1)
239 yield bus.w_data.eq(0xaa)
240 yield
241 self.assertEqual((yield elem_20_rw.w_stb), 0)
242 yield bus.addr.eq(2)
243 yield bus.w_data.eq(0x33)
244 yield
245 self.assertEqual((yield elem_20_rw.w_stb), 0)
246 yield bus.addr.eq(3)
247 yield bus.w_data.eq(0xdd)
248 yield
249 self.assertEqual((yield elem_20_rw.w_stb), 0)
250 yield bus.w_stb.eq(0)
251 yield
252 self.assertEqual((yield elem_20_rw.w_stb), 1)
253 self.assertEqual((yield elem_20_rw.w_data), 0x3aa55)
254
255 with Simulator(self.dut, vcd_file=open("test.vcd", "w")) as sim:
256 sim.add_clock(1e-6)
257 sim.add_sync_process(sim_test())
258 sim.run()
259
260
261 class DecoderTestCase(unittest.TestCase):
262 def setUp(self):
263 self.dut = Decoder(addr_width=16, data_width=8)
264 Fragment.get(self.dut, platform=None) # silence UnusedElaboratable
265
266 def test_add_wrong_sub_bus(self):
267 with self.assertRaisesRegex(TypeError,
268 r"Subordinate bus must be an instance of csr\.Interface, not 1"):
269 self.dut.add(1)
270
271 def test_add_wrong_data_width(self):
272 mux = Multiplexer(addr_width=10, data_width=16)
273 Fragment.get(mux, platform=None) # silence UnusedElaboratable
274
275 with self.assertRaisesRegex(ValueError,
276 r"Subordinate bus has data width 16, which is not the same as "
277 r"multiplexer data width 8"):
278 self.dut.add(mux.bus)
279
280 def test_sim(self):
281 mux_1 = Multiplexer(addr_width=10, data_width=8)
282 self.dut.add(mux_1.bus)
283 elem_1 = Element(8, "rw")
284 mux_1.add(elem_1)
285
286 mux_2 = Multiplexer(addr_width=10, data_width=8)
287 self.dut.add(mux_2.bus)
288 elem_2 = Element(8, "rw")
289 mux_2.add(elem_2, addr=2)
290
291 elem_1_addr, _, _ = self.dut.bus.memory_map.find_resource(elem_1)
292 elem_2_addr, _, _ = self.dut.bus.memory_map.find_resource(elem_2)
293 self.assertEqual(elem_1_addr, 0x0000)
294 self.assertEqual(elem_2_addr, 0x0402)
295
296 bus = self.dut.bus
297
298 def sim_test():
299 yield bus.addr.eq(elem_1_addr)
300 yield bus.w_stb.eq(1)
301 yield bus.w_data.eq(0x55)
302 yield
303 yield bus.w_stb.eq(0)
304 yield
305 self.assertEqual((yield elem_1.w_data), 0x55)
306
307 yield bus.addr.eq(elem_2_addr)
308 yield bus.w_stb.eq(1)
309 yield bus.w_data.eq(0xaa)
310 yield
311 yield bus.w_stb.eq(0)
312 yield
313 self.assertEqual((yield elem_2.w_data), 0xaa)
314
315 yield elem_1.r_data.eq(0x55)
316 yield elem_2.r_data.eq(0xaa)
317
318 yield bus.addr.eq(elem_1_addr)
319 yield bus.r_stb.eq(1)
320 yield
321 yield bus.addr.eq(elem_2_addr)
322 yield
323 self.assertEqual((yield bus.r_data), 0x55)
324 yield
325 self.assertEqual((yield bus.r_data), 0xaa)
326
327 m = Module()
328 m.submodules += self.dut, mux_1, mux_2
329 with Simulator(m, vcd_file=open("test.vcd", "w")) as sim:
330 sim.add_clock(1e-6)
331 sim.add_sync_process(sim_test())
332 sim.run()