wishbone.bus: add Decoder.
[nmigen-soc.git] / nmigen_soc / test / test_wishbone_bus.py
1 # nmigen: UnusedElaboratable=no
2
3 import unittest
4 from nmigen import *
5 from nmigen.hdl.rec import *
6 from nmigen.back.pysim import *
7
8 from ..wishbone.bus import *
9
10
11 class InterfaceTestCase(unittest.TestCase):
12 def test_simple(self):
13 iface = Interface(addr_width=32, data_width=8)
14 self.assertEqual(iface.addr_width, 32)
15 self.assertEqual(iface.data_width, 8)
16 self.assertEqual(iface.granularity, 8)
17 self.assertEqual(iface.memory_map.addr_width, 32)
18 self.assertEqual(iface.memory_map.data_width, 8)
19 self.assertEqual(iface.layout, Layout.cast([
20 ("adr", 32, DIR_FANOUT),
21 ("dat_w", 8, DIR_FANOUT),
22 ("dat_r", 8, DIR_FANIN),
23 ("sel", 1, DIR_FANOUT),
24 ("cyc", 1, DIR_FANOUT),
25 ("stb", 1, DIR_FANOUT),
26 ("we", 1, DIR_FANOUT),
27 ("ack", 1, DIR_FANIN),
28 ]))
29
30 def test_granularity(self):
31 iface = Interface(addr_width=30, data_width=32, granularity=8)
32 self.assertEqual(iface.addr_width, 30)
33 self.assertEqual(iface.data_width, 32)
34 self.assertEqual(iface.granularity, 8)
35 self.assertEqual(iface.memory_map.addr_width, 32)
36 self.assertEqual(iface.memory_map.data_width, 8)
37 self.assertEqual(iface.layout, Layout.cast([
38 ("adr", 30, DIR_FANOUT),
39 ("dat_w", 32, DIR_FANOUT),
40 ("dat_r", 32, DIR_FANIN),
41 ("sel", 4, DIR_FANOUT),
42 ("cyc", 1, DIR_FANOUT),
43 ("stb", 1, DIR_FANOUT),
44 ("we", 1, DIR_FANOUT),
45 ("ack", 1, DIR_FANIN),
46 ]))
47
48 def test_features(self):
49 iface = Interface(addr_width=32, data_width=32,
50 features={"rty", "err", "stall", "lock", "cti", "bte"})
51 self.assertEqual(iface.layout, Layout.cast([
52 ("adr", 32, DIR_FANOUT),
53 ("dat_w", 32, DIR_FANOUT),
54 ("dat_r", 32, DIR_FANIN),
55 ("sel", 1, DIR_FANOUT),
56 ("cyc", 1, DIR_FANOUT),
57 ("stb", 1, DIR_FANOUT),
58 ("we", 1, DIR_FANOUT),
59 ("ack", 1, DIR_FANIN),
60 ("err", 1, DIR_FANIN),
61 ("rty", 1, DIR_FANIN),
62 ("stall", 1, DIR_FANIN),
63 ("lock", 1, DIR_FANOUT),
64 ("cti", CycleType, DIR_FANOUT),
65 ("bte", BurstTypeExt, DIR_FANOUT),
66 ]))
67
68 def test_wrong_addr_width(self):
69 with self.assertRaisesRegex(ValueError,
70 r"Address width must be a non-negative integer, not -1"):
71 Interface(addr_width=-1, data_width=8)
72
73 def test_wrong_data_width(self):
74 with self.assertRaisesRegex(ValueError,
75 r"Data width must be one of 8, 16, 32, 64, not 7"):
76 Interface(addr_width=0, data_width=7)
77
78 def test_wrong_granularity(self):
79 with self.assertRaisesRegex(ValueError,
80 r"Granularity must be one of 8, 16, 32, 64, not 7"):
81 Interface(addr_width=0, data_width=32, granularity=7)
82
83 def test_wrong_granularity_wide(self):
84 with self.assertRaisesRegex(ValueError,
85 r"Granularity 32 may not be greater than data width 8"):
86 Interface(addr_width=0, data_width=8, granularity=32)
87
88 def test_wrong_features(self):
89 with self.assertRaisesRegex(ValueError,
90 r"Optional signal\(s\) 'foo' are not supported"):
91 Interface(addr_width=0, data_width=8, features={"foo"})
92
93
94 class DecoderTestCase(unittest.TestCase):
95 def setUp(self):
96 self.dut = Decoder(addr_width=31, data_width=32, granularity=16)
97
98 def test_add_align_to(self):
99 sub_1 = Interface(addr_width=15, data_width=32, granularity=16)
100 sub_2 = Interface(addr_width=15, data_width=32, granularity=16)
101 self.assertEqual(self.dut.add(sub_1), (0x00000000, 0x00010000, 1))
102 self.assertEqual(self.dut.align_to(18), 0x000040000)
103 self.assertEqual(self.dut.add(sub_2), (0x00040000, 0x00050000, 1))
104
105 def test_add_wrong(self):
106 with self.assertRaisesRegex(TypeError,
107 r"Subordinate bus must be an instance of wishbone\.Interface, not 'foo'"):
108 self.dut.add("foo")
109
110 def test_add_wrong_granularity(self):
111 with self.assertRaisesRegex(ValueError,
112 r"Subordinate bus has granularity 32, which is greater than "
113 r"the decoder granularity 16"):
114 self.dut.add(Interface(addr_width=15, data_width=32, granularity=32))
115
116 def test_add_wrong_width_dense(self):
117 with self.assertRaisesRegex(ValueError,
118 r"Subordinate bus has data width 16, which is not the same as decoder "
119 r"data width 32 \(required for dense address translation\)"):
120 self.dut.add(Interface(addr_width=15, data_width=16, granularity=16))
121
122 def test_add_wrong_granularity_sparse(self):
123 with self.assertRaisesRegex(ValueError,
124 r"Subordinate bus has data width 64, which is not the same as subordinate "
125 r"bus granularity 16 \(required for sparse address translation\)"):
126 self.dut.add(Interface(addr_width=15, data_width=64, granularity=16), sparse=True)
127
128 def test_add_wrong_optional_output(self):
129 with self.assertRaisesRegex(ValueError,
130 r"Subordinate bus has optional output 'err', but the decoder does "
131 r"not have a corresponding input"):
132 self.dut.add(Interface(addr_width=15, data_width=32, granularity=16, features={"err"}))
133
134
135 class DecoderSimulationTestCase(unittest.TestCase):
136 def test_simple(self):
137 dut = Decoder(addr_width=30, data_width=32, granularity=8,
138 features={"err", "rty", "stall", "lock", "cti", "bte"})
139 sub_1 = Interface(addr_width=14, data_width=32, granularity=8)
140 dut.add(sub_1, addr=0x10000)
141 sub_2 = Interface(addr_width=14, data_width=32, granularity=8,
142 features={"err", "rty", "stall", "lock", "cti", "bte"})
143 dut.add(sub_2)
144
145 def sim_test():
146 yield dut.bus.adr.eq(0x10400 >> 2)
147 yield dut.bus.cyc.eq(1)
148 yield dut.bus.stb.eq(1)
149 yield dut.bus.sel.eq(0b11)
150 yield dut.bus.dat_w.eq(0x12345678)
151 yield dut.bus.lock.eq(1)
152 yield dut.bus.cti.eq(CycleType.INCR_BURST)
153 yield dut.bus.bte.eq(BurstTypeExt.WRAP_4)
154 yield sub_1.ack.eq(1)
155 yield sub_1.dat_r.eq(0xabcdef01)
156 yield sub_2.dat_r.eq(0x5678abcd)
157 yield Delay(1e-6)
158 self.assertEqual((yield sub_1.adr), 0x400 >> 2)
159 self.assertEqual((yield sub_1.cyc), 1)
160 self.assertEqual((yield sub_2.cyc), 0)
161 self.assertEqual((yield sub_1.stb), 1)
162 self.assertEqual((yield sub_1.sel), 0b11)
163 self.assertEqual((yield sub_1.dat_w), 0x12345678)
164 self.assertEqual((yield dut.bus.ack), 1)
165 self.assertEqual((yield dut.bus.err), 0)
166 self.assertEqual((yield dut.bus.rty), 0)
167 self.assertEqual((yield dut.bus.dat_r), 0xabcdef01)
168
169 yield dut.bus.adr.eq(0x20400 >> 2)
170 yield sub_1.ack.eq(0)
171 yield sub_2.err.eq(1)
172 yield sub_2.rty.eq(1)
173 yield sub_2.stall.eq(1)
174 yield Delay(1e-6)
175 self.assertEqual((yield sub_2.adr), 0x400 >> 2)
176 self.assertEqual((yield sub_1.cyc), 0)
177 self.assertEqual((yield sub_2.cyc), 1)
178 self.assertEqual((yield sub_1.stb), 1)
179 self.assertEqual((yield sub_1.sel), 0b11)
180 self.assertEqual((yield sub_1.dat_w), 0x12345678)
181 self.assertEqual((yield sub_2.lock), 1)
182 self.assertEqual((yield sub_2.cti), CycleType.INCR_BURST.value)
183 self.assertEqual((yield sub_2.bte), BurstTypeExt.WRAP_4.value)
184 self.assertEqual((yield dut.bus.ack), 0)
185 self.assertEqual((yield dut.bus.err), 1)
186 self.assertEqual((yield dut.bus.rty), 1)
187 self.assertEqual((yield dut.bus.stall), 1)
188 self.assertEqual((yield dut.bus.dat_r), 0x5678abcd)
189
190 with Simulator(dut, vcd_file=open("test.vcd", "w")) as sim:
191 sim.add_process(sim_test())
192 sim.run()
193
194 def test_addr_translate(self):
195 class AddressLoopback(Elaboratable):
196 def __init__(self, **kwargs):
197 self.bus = Interface(**kwargs)
198
199 def elaborate(self, platform):
200 m = Module()
201
202 for index, sel_bit in enumerate(self.bus.sel):
203 with m.If(sel_bit):
204 segment = self.bus.dat_r.word_select(index, self.bus.granularity)
205 m.d.comb += segment.eq(self.bus.adr + index)
206
207 return m
208
209 dut = Decoder(addr_width=20, data_width=32, granularity=16)
210 loop_1 = AddressLoopback(addr_width=7, data_width=32, granularity=16)
211 self.assertEqual(dut.add(loop_1.bus, addr=0x10000),
212 (0x10000, 0x10100, 1))
213 loop_2 = AddressLoopback(addr_width=6, data_width=32, granularity=8)
214 self.assertEqual(dut.add(loop_2.bus, addr=0x20000),
215 (0x20000, 0x20080, 2))
216 loop_3 = AddressLoopback(addr_width=8, data_width=16, granularity=16)
217 self.assertEqual(dut.add(loop_3.bus, addr=0x30000, sparse=True),
218 (0x30000, 0x30100, 1))
219 loop_4 = AddressLoopback(addr_width=8, data_width=8, granularity=8)
220 self.assertEqual(dut.add(loop_4.bus, addr=0x40000, sparse=True),
221 (0x40000, 0x40100, 1))
222
223 def sim_test():
224 yield dut.bus.cyc.eq(1)
225
226 yield dut.bus.adr.eq(0x10010 >> 1)
227
228 yield dut.bus.sel.eq(0b11)
229 yield Delay(1e-6)
230 self.assertEqual((yield dut.bus.dat_r), 0x00090008)
231
232 yield dut.bus.sel.eq(0b01)
233 yield Delay(1e-6)
234 self.assertEqual((yield dut.bus.dat_r), 0x00000008)
235
236 yield dut.bus.sel.eq(0b10)
237 yield Delay(1e-6)
238 self.assertEqual((yield dut.bus.dat_r), 0x00090000)
239
240 yield dut.bus.adr.eq(0x20010 >> 1)
241
242 yield dut.bus.sel.eq(0b11)
243 yield Delay(1e-6)
244 self.assertEqual((yield dut.bus.dat_r), 0x13121110)
245
246 yield dut.bus.sel.eq(0b01)
247 yield Delay(1e-6)
248 self.assertEqual((yield dut.bus.dat_r), 0x00001110)
249
250 yield dut.bus.sel.eq(0b10)
251 yield Delay(1e-6)
252 self.assertEqual((yield dut.bus.dat_r), 0x13120000)
253
254 yield dut.bus.adr.eq(0x30010 >> 1)
255
256 yield dut.bus.sel.eq(0b11)
257 yield Delay(1e-6)
258 self.assertEqual((yield dut.bus.dat_r), 0x0008)
259
260 yield dut.bus.sel.eq(0b01)
261 yield Delay(1e-6)
262 self.assertEqual((yield dut.bus.dat_r), 0x0008)
263
264 yield dut.bus.sel.eq(0b10)
265 yield Delay(1e-6)
266 self.assertEqual((yield dut.bus.dat_r), 0x0000)
267
268 yield dut.bus.adr.eq(0x30012 >> 1)
269
270 yield dut.bus.sel.eq(0b11)
271 yield Delay(1e-6)
272 self.assertEqual((yield dut.bus.dat_r), 0x0009)
273
274 yield dut.bus.adr.eq(0x40010 >> 1)
275
276 yield dut.bus.sel.eq(0b11)
277 yield Delay(1e-6)
278 self.assertEqual((yield dut.bus.dat_r), 0x08)
279
280 yield dut.bus.sel.eq(0b01)
281 yield Delay(1e-6)
282 self.assertEqual((yield dut.bus.dat_r), 0x08)
283
284 yield dut.bus.sel.eq(0b10)
285 yield Delay(1e-6)
286 self.assertEqual((yield dut.bus.dat_r), 0x00)
287
288 yield dut.bus.adr.eq(0x40012 >> 1)
289
290 yield dut.bus.sel.eq(0b11)
291 yield Delay(1e-6)
292 self.assertEqual((yield dut.bus.dat_r), 0x09)
293
294 m = Module()
295 m.submodules += dut, loop_1, loop_2, loop_3, loop_4
296 with Simulator(m, vcd_file=open("test.vcd", "w")) as sim:
297 sim.add_process(sim_test())
298 sim.run()