csr.bus: rewrite using the MemoryMap abstraction.
[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_addr_width_wrong(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_data_width_wrong(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 DecoderTestCase(unittest.TestCase):
86 def setUp(self):
87 self.dut = Decoder(addr_width=16, data_width=8)
88
89 def test_add_4b(self):
90 self.assertEqual(self.dut.add(Element(4, "rw")),
91 (0, 1))
92
93 def test_add_8b(self):
94 self.assertEqual(self.dut.add(Element(8, "rw")),
95 (0, 1))
96
97 def test_add_12b(self):
98 self.assertEqual(self.dut.add(Element(12, "rw")),
99 (0, 2))
100
101 def test_add_16b(self):
102 self.assertEqual(self.dut.add(Element(16, "rw")),
103 (0, 2))
104
105 def test_add_two(self):
106 self.assertEqual(self.dut.add(Element(16, "rw")),
107 (0, 2))
108 self.assertEqual(self.dut.add(Element(8, "rw")),
109 (2, 3))
110
111 def test_add_wrong(self):
112 with self.assertRaisesRegex(ValueError,
113 r"Width must be a non-negative integer, not -1"):
114 Element(-1, "rw")
115
116 def test_align_to(self):
117 self.assertEqual(self.dut.add(Element(8, "rw")),
118 (0, 1))
119 self.assertEqual(self.dut.align_to(2), 4)
120 self.assertEqual(self.dut.add(Element(8, "rw")),
121 (4, 5))
122
123 def test_sim(self):
124 bus = self.dut.bus
125
126 elem_4_r = Element(4, "r")
127 self.dut.add(elem_4_r)
128 elem_8_w = Element(8, "w")
129 self.dut.add(elem_8_w)
130 elem_16_rw = Element(16, "rw")
131 self.dut.add(elem_16_rw)
132
133 def sim_test():
134 yield elem_4_r.r_data.eq(0xa)
135 yield elem_16_rw.r_data.eq(0x5aa5)
136
137 yield bus.addr.eq(0)
138 yield bus.r_stb.eq(1)
139 yield
140 yield bus.r_stb.eq(0)
141 self.assertEqual((yield elem_4_r.r_stb), 1)
142 self.assertEqual((yield elem_16_rw.r_stb), 0)
143 yield
144 self.assertEqual((yield bus.r_data), 0xa)
145
146 yield bus.addr.eq(2)
147 yield bus.r_stb.eq(1)
148 yield
149 yield bus.r_stb.eq(0)
150 self.assertEqual((yield elem_4_r.r_stb), 0)
151 self.assertEqual((yield elem_16_rw.r_stb), 1)
152 yield
153 yield bus.addr.eq(3) # pipeline a read
154 self.assertEqual((yield bus.r_data), 0xa5)
155
156 yield bus.r_stb.eq(1)
157 yield
158 yield bus.r_stb.eq(0)
159 self.assertEqual((yield elem_4_r.r_stb), 0)
160 self.assertEqual((yield elem_16_rw.r_stb), 0)
161 yield
162 self.assertEqual((yield bus.r_data), 0x5a)
163
164 yield bus.addr.eq(1)
165 yield bus.w_data.eq(0x3d)
166 yield bus.w_stb.eq(1)
167 yield
168 yield bus.w_stb.eq(0)
169 yield
170 self.assertEqual((yield elem_8_w.w_stb), 1)
171 self.assertEqual((yield elem_8_w.w_data), 0x3d)
172 self.assertEqual((yield elem_16_rw.w_stb), 0)
173
174 yield bus.addr.eq(2)
175 yield bus.w_data.eq(0x55)
176 yield bus.w_stb.eq(1)
177 yield
178 self.assertEqual((yield elem_8_w.w_stb), 0)
179 self.assertEqual((yield elem_16_rw.w_stb), 0)
180 yield bus.addr.eq(3) # pipeline a write
181 yield bus.w_data.eq(0xaa)
182 yield
183 self.assertEqual((yield elem_8_w.w_stb), 0)
184 self.assertEqual((yield elem_16_rw.w_stb), 0)
185 yield bus.w_stb.eq(0)
186 yield
187 self.assertEqual((yield elem_8_w.w_stb), 0)
188 self.assertEqual((yield elem_16_rw.w_stb), 1)
189 self.assertEqual((yield elem_16_rw.w_data), 0xaa55)
190
191 with Simulator(self.dut, vcd_file=open("test.vcd", "w")) as sim:
192 sim.add_clock(1e-6)
193 sim.add_sync_process(sim_test())
194 sim.run()
195
196
197 class DecoderAlignedTestCase(unittest.TestCase):
198 def setUp(self):
199 self.dut = Decoder(addr_width=16, data_width=8, alignment=2)
200
201 def test_add_two(self):
202 self.assertEqual(self.dut.add(Element(8, "rw")),
203 (0, 4))
204 self.assertEqual(self.dut.add(Element(16, "rw")),
205 (4, 8))
206
207 def test_over_align_to(self):
208 self.assertEqual(self.dut.add(Element(8, "rw")),
209 (0, 4))
210 self.assertEqual(self.dut.align_to(3), 8)
211 self.assertEqual(self.dut.add(Element(8, "rw")),
212 (8, 12))
213
214 def test_under_align_to(self):
215 self.assertEqual(self.dut.add(Element(8, "rw")),
216 (0, 4))
217 self.assertEqual(self.dut.align_to(1), 4)
218 self.assertEqual(self.dut.add(Element(8, "rw")),
219 (4, 8))
220
221 def test_sim(self):
222 bus = self.dut.bus
223
224 elem_20_rw = Element(20, "rw")
225 self.dut.add(elem_20_rw)
226
227 def sim_test():
228 yield bus.w_stb.eq(1)
229 yield bus.addr.eq(0)
230 yield bus.w_data.eq(0x55)
231 yield
232 self.assertEqual((yield elem_20_rw.w_stb), 0)
233 yield bus.addr.eq(1)
234 yield bus.w_data.eq(0xaa)
235 yield
236 self.assertEqual((yield elem_20_rw.w_stb), 0)
237 yield bus.addr.eq(2)
238 yield bus.w_data.eq(0x33)
239 yield
240 self.assertEqual((yield elem_20_rw.w_stb), 0)
241 yield bus.addr.eq(3)
242 yield bus.w_data.eq(0xdd)
243 yield
244 self.assertEqual((yield elem_20_rw.w_stb), 0)
245 yield bus.w_stb.eq(0)
246 yield
247 self.assertEqual((yield elem_20_rw.w_stb), 1)
248 self.assertEqual((yield elem_20_rw.w_data), 0x3aa55)
249
250 with Simulator(self.dut, vcd_file=open("test.vcd", "w")) as sim:
251 sim.add_clock(1e-6)
252 sim.add_sync_process(sim_test())
253 sim.run()