csr.bus: add CSRElement and CSRMultiplexer.
[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 CSRElementTestCase(unittest.TestCase):
10 def test_1_ro(self):
11 elem = CSRElement(1, "r")
12 self.assertEqual(elem.width, 1)
13 self.assertEqual(elem.access, "r")
14 self.assertEqual(elem.layout, Layout.cast([
15 ("r_data", 1),
16 ("r_stb", 1),
17 ]))
18
19 def test_8_rw(self):
20 elem = CSRElement(8, access="rw")
21 self.assertEqual(elem.width, 8)
22 self.assertEqual(elem.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_10_wo(self):
31 elem = CSRElement(10, "w")
32 self.assertEqual(elem.width, 10)
33 self.assertEqual(elem.access, "w")
34 self.assertEqual(elem.layout, Layout.cast([
35 ("w_data", 10),
36 ("w_stb", 1),
37 ]))
38
39 def test_0_rw(self): # degenerate but legal case
40 elem = CSRElement(0, access="rw")
41 self.assertEqual(elem.width, 0)
42 self.assertEqual(elem.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 CSRElement(-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 CSRElement(1, "wo")
59
60
61 class CSRMultiplexerTestCase(unittest.TestCase):
62 def setUp(self):
63 self.dut = CSRMultiplexer(addr_width=16, data_width=8)
64
65 def test_addr_width_wrong(self):
66 with self.assertRaisesRegex(ValueError,
67 r"Address width must be a positive integer, not -1"):
68 CSRMultiplexer(addr_width=-1, data_width=8)
69
70 def test_data_width_wrong(self):
71 with self.assertRaisesRegex(ValueError,
72 r"Data width must be a positive integer, not -1"):
73 CSRMultiplexer(addr_width=16, data_width=-1)
74
75 def test_alignment_wrong(self):
76 with self.assertRaisesRegex(ValueError,
77 r"Alignment must be a non-negative integer, not -1"):
78 CSRMultiplexer(addr_width=16, data_width=8, alignment=-1)
79
80 def test_attrs(self):
81 self.assertEqual(self.dut.addr_width, 16)
82 self.assertEqual(self.dut.data_width, 8)
83 self.assertEqual(self.dut.alignment, 0)
84
85 def test_add_4b(self):
86 self.assertEqual(self.dut.add(CSRElement(4, "rw")),
87 (0, 1))
88
89 def test_add_8b(self):
90 self.assertEqual(self.dut.add(CSRElement(8, "rw")),
91 (0, 1))
92
93 def test_add_12b(self):
94 self.assertEqual(self.dut.add(CSRElement(12, "rw")),
95 (0, 2))
96
97 def test_add_16b(self):
98 self.assertEqual(self.dut.add(CSRElement(16, "rw")),
99 (0, 2))
100
101 def test_add_two(self):
102 self.assertEqual(self.dut.add(CSRElement(16, "rw")),
103 (0, 2))
104 self.assertEqual(self.dut.add(CSRElement(8, "rw")),
105 (2, 1))
106
107 def test_add_wrong(self):
108 with self.assertRaisesRegex(ValueError,
109 r"Width must be a non-negative integer, not -1"):
110 CSRElement(-1, "rw")
111
112 def test_align_to(self):
113 self.assertEqual(self.dut.add(CSRElement(8, "rw")),
114 (0, 1))
115 self.assertEqual(self.dut.align_to(2), 4)
116 self.assertEqual(self.dut.add(CSRElement(8, "rw")),
117 (4, 1))
118
119 def test_sim(self):
120 elem_4_r = CSRElement(4, "r")
121 self.dut.add(elem_4_r)
122 elem_8_w = CSRElement(8, "w")
123 self.dut.add(elem_8_w)
124 elem_16_rw = CSRElement(16, "rw")
125 self.dut.add(elem_16_rw)
126
127 def sim_test():
128 yield elem_4_r.r_data.eq(0xa)
129 yield elem_16_rw.r_data.eq(0x5aa5)
130
131 yield self.dut.addr.eq(0)
132 yield self.dut.r_stb.eq(1)
133 yield
134 yield self.dut.r_stb.eq(0)
135 self.assertEqual((yield elem_4_r.r_stb), 1)
136 self.assertEqual((yield elem_16_rw.r_stb), 0)
137 yield
138 self.assertEqual((yield self.dut.r_data), 0xa)
139
140 yield self.dut.addr.eq(2)
141 yield self.dut.r_stb.eq(1)
142 yield
143 yield self.dut.r_stb.eq(0)
144 self.assertEqual((yield elem_4_r.r_stb), 0)
145 self.assertEqual((yield elem_16_rw.r_stb), 1)
146 yield
147 yield self.dut.addr.eq(3) # pipeline a read
148 self.assertEqual((yield self.dut.r_data), 0xa5)
149
150 yield self.dut.r_stb.eq(1)
151 yield
152 yield self.dut.r_stb.eq(0)
153 self.assertEqual((yield elem_4_r.r_stb), 0)
154 self.assertEqual((yield elem_16_rw.r_stb), 0)
155 yield
156 self.assertEqual((yield self.dut.r_data), 0x5a)
157
158 yield self.dut.addr.eq(1)
159 yield self.dut.w_data.eq(0x3d)
160 yield self.dut.w_stb.eq(1)
161 yield
162 yield self.dut.w_stb.eq(0)
163 yield
164 self.assertEqual((yield elem_8_w.w_stb), 1)
165 self.assertEqual((yield elem_8_w.w_data), 0x3d)
166 self.assertEqual((yield elem_16_rw.w_stb), 0)
167
168 yield self.dut.addr.eq(2)
169 yield self.dut.w_data.eq(0x55)
170 yield self.dut.w_stb.eq(1)
171 yield
172 self.assertEqual((yield elem_8_w.w_stb), 0)
173 self.assertEqual((yield elem_16_rw.w_stb), 0)
174 yield self.dut.addr.eq(3) # pipeline a write
175 yield self.dut.w_data.eq(0xaa)
176 yield
177 self.assertEqual((yield elem_8_w.w_stb), 0)
178 self.assertEqual((yield elem_16_rw.w_stb), 0)
179 yield self.dut.w_stb.eq(0)
180 yield
181 self.assertEqual((yield elem_8_w.w_stb), 0)
182 self.assertEqual((yield elem_16_rw.w_stb), 1)
183 self.assertEqual((yield elem_16_rw.w_data), 0xaa55)
184
185 with Simulator(self.dut, vcd_file=open("test.vcd", "w")) as sim:
186 sim.add_clock(1e-6)
187 sim.add_sync_process(sim_test())
188 sim.run()
189
190
191 class CSRAlignedMultiplexerTestCase(unittest.TestCase):
192 def setUp(self):
193 self.dut = CSRMultiplexer(addr_width=16, data_width=8, alignment=2)
194
195 def test_attrs(self):
196 self.assertEqual(self.dut.alignment, 2)
197
198 def test_add_two(self):
199 self.assertEqual(self.dut.add(CSRElement(8, "rw")),
200 (0, 4))
201 self.assertEqual(self.dut.add(CSRElement(16, "rw")),
202 (4, 4))
203
204 def test_over_align_to(self):
205 self.assertEqual(self.dut.add(CSRElement(8, "rw")),
206 (0, 4))
207 self.assertEqual(self.dut.align_to(3), 8)
208 self.assertEqual(self.dut.add(CSRElement(8, "rw")),
209 (8, 4))
210
211 def test_under_align_to(self):
212 self.assertEqual(self.dut.add(CSRElement(8, "rw")),
213 (0, 4))
214 self.assertEqual(self.dut.align_to(1), 4)
215 self.assertEqual(self.dut.add(CSRElement(8, "rw")),
216 (4, 4))
217
218 def test_sim(self):
219 elem_20_rw = CSRElement(20, "rw")
220 self.dut.add(elem_20_rw)
221
222 def sim_test():
223 yield self.dut.w_stb.eq(1)
224 yield self.dut.addr.eq(0)
225 yield self.dut.w_data.eq(0x55)
226 yield
227 self.assertEqual((yield elem_20_rw.w_stb), 0)
228 yield self.dut.addr.eq(1)
229 yield self.dut.w_data.eq(0xaa)
230 yield
231 self.assertEqual((yield elem_20_rw.w_stb), 0)
232 yield self.dut.addr.eq(2)
233 yield self.dut.w_data.eq(0x33)
234 yield
235 self.assertEqual((yield elem_20_rw.w_stb), 0)
236 yield self.dut.addr.eq(3)
237 yield self.dut.w_data.eq(0xdd)
238 yield
239 self.assertEqual((yield elem_20_rw.w_stb), 0)
240 yield self.dut.w_stb.eq(0)
241 yield
242 self.assertEqual((yield elem_20_rw.w_stb), 1)
243 self.assertEqual((yield elem_20_rw.w_data), 0x3aa55)
244
245 with Simulator(self.dut, vcd_file=open("test.vcd", "w")) as sim:
246 sim.add_clock(1e-6)
247 sim.add_sync_process(sim_test())
248 sim.run()