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