whitespace cleanup
[nmigen-soc.git] / nmigen_soc / test / test_memory.py
1 import unittest
2
3 from ..memory import _RangeMap, MemoryMap
4
5
6 class RangeMapTestCase(unittest.TestCase):
7 def test_insert(self):
8 range_map = _RangeMap()
9 range_map.insert(range(0,10), "a")
10 range_map.insert(range(20,21), "c")
11 range_map.insert(range(15,16), "b")
12 range_map.insert(range(16,20), "q")
13 self.assertEqual(range_map._keys, [
14 range(0,10), range(15,16), range(16,20), range(20,21)
15 ])
16
17 def test_overlaps(self):
18 range_map = _RangeMap()
19 range_map.insert(range(10,20), "a")
20 self.assertEqual(range_map.overlaps(range(5,15)), ["a"])
21 self.assertEqual(range_map.overlaps(range(15,25)), ["a"])
22 self.assertEqual(range_map.overlaps(range(5,25)), ["a"])
23 self.assertEqual(range_map.overlaps(range(0,3)), [])
24 self.assertEqual(range_map.overlaps(range(0,5)), [])
25 self.assertEqual(range_map.overlaps(range(25,30)), [])
26
27 def test_insert_wrong_overlap(self):
28 range_map = _RangeMap()
29 range_map.insert(range(0,10), "a")
30 with self.assertRaises(AssertionError):
31 range_map.insert(range(5,15), "b")
32
33 def test_get(self):
34 range_map = _RangeMap()
35 range_map.insert(range(5,15), "a")
36 self.assertEqual(range_map.get(0), None)
37 self.assertEqual(range_map.get(5), "a")
38 self.assertEqual(range_map.get(10), "a")
39 self.assertEqual(range_map.get(14), "a")
40 self.assertEqual(range_map.get(15), None)
41
42
43 class MemoryMapTestCase(unittest.TestCase):
44 def test_wrong_addr_width(self):
45 with self.assertRaisesRegex(ValueError,
46 r"Address width must be a positive integer, not -1"):
47 MemoryMap(addr_width=-1, data_width=8)
48
49 def test_wrong_data_width(self):
50 with self.assertRaisesRegex(ValueError,
51 r"Data width must be a positive integer, not -1"):
52 MemoryMap(addr_width=16, data_width=-1)
53
54 def test_wrong_alignment(self):
55 with self.assertRaisesRegex(ValueError,
56 r"Alignment must be a non-negative integer, not -1"):
57 MemoryMap(addr_width=16, data_width=8, alignment=-1)
58
59 def test_add_resource(self):
60 memory_map = MemoryMap(addr_width=16, data_width=8)
61 self.assertEqual(memory_map.add_resource("a", size=1), (0, 1))
62 self.assertEqual(memory_map.add_resource("b", size=2), (1, 3))
63
64 def test_add_resource_map_aligned(self):
65 memory_map = MemoryMap(addr_width=16, data_width=8, alignment=1)
66 self.assertEqual(memory_map.add_resource("a", size=1), (0, 2))
67 self.assertEqual(memory_map.add_resource("b", size=2), (2, 4))
68
69 def test_add_resource_explicit_aligned(self):
70 memory_map = MemoryMap(addr_width=16, data_width=8)
71 self.assertEqual(memory_map.add_resource("a", size=1), (0, 1))
72 self.assertEqual(memory_map.add_resource("b", size=1, alignment=1), (2, 4))
73 self.assertEqual(memory_map.add_resource("c", size=2), (4, 6))
74
75 def test_add_resource_addr(self):
76 memory_map = MemoryMap(addr_width=16, data_width=8)
77 self.assertEqual(memory_map.add_resource("a", size=1, addr=10), (10, 11))
78 self.assertEqual(memory_map.add_resource("b", size=2), (11, 13))
79
80 def test_add_resource_wrong_address(self):
81 memory_map = MemoryMap(addr_width=16, data_width=8)
82 with self.assertRaisesRegex(ValueError,
83 r"Address must be a non-negative integer, not -1"):
84 memory_map.add_resource("a", size=1, addr=-1)
85
86 def test_add_resource_wrong_address_unaligned(self):
87 memory_map = MemoryMap(addr_width=16, data_width=8, alignment=1)
88 with self.assertRaisesRegex(ValueError,
89 r"Explicitly specified address 0x1 must be "
90 r"a multiple of 0x2 bytes"):
91 memory_map.add_resource("a", size=1, addr=1)
92
93 def test_add_resource_wrong_size(self):
94 memory_map = MemoryMap(addr_width=16, data_width=8)
95 with self.assertRaisesRegex(ValueError,
96 r"Size must be a non-negative integer, not -1"):
97 memory_map.add_resource("a", size=-1)
98
99 def test_add_resource_wrong_alignment(self):
100 memory_map = MemoryMap(addr_width=16, data_width=8)
101 with self.assertRaisesRegex(ValueError,
102 r"Alignment must be a non-negative integer, not -1"):
103 memory_map.add_resource("a", size=1, alignment=-1)
104
105 def test_add_resource_wrong_out_of_bounds(self):
106 memory_map = MemoryMap(addr_width=16, data_width=8)
107 with self.assertRaisesRegex(ValueError,
108 r"Address range 0x10000\.\.0x10001 out of bounds for memory "
109 r"map spanning range 0x0\.\.0x10000 \(16 address bits\)"):
110 memory_map.add_resource("a", addr=0x10000, size=1)
111 with self.assertRaisesRegex(ValueError,
112 r"Address range 0x0\.\.0x10001 out of bounds for memory map "
113 r"spanning range 0x0\.\.0x10000 \(16 address bits\)"):
114 memory_map.add_resource("a", size=0x10001)
115
116 def test_add_resource_wrong_overlap(self):
117 memory_map = MemoryMap(addr_width=16, data_width=8)
118 memory_map.add_resource("a", size=16)
119 with self.assertRaisesRegex(ValueError,
120 r"Address range 0xa\.\.0xb overlaps with resource "
121 r"'a' at 0x0\.\.0x10"):
122 memory_map.add_resource("b", size=1, addr=10)
123
124 def test_add_resource_wrong_twice(self):
125 memory_map = MemoryMap(addr_width=16, data_width=8)
126 memory_map.add_resource("a", size=16)
127 with self.assertRaisesRegex(ValueError,
128 r"Resource 'a' is already added at address range 0x0..0x10"):
129 memory_map.add_resource("a", size=16)
130
131 def test_iter_resources(self):
132 memory_map = MemoryMap(addr_width=16, data_width=8)
133 memory_map.add_resource("a", size=1)
134 memory_map.add_resource("b", size=2)
135 self.assertEqual(list(memory_map.resources()), [
136 ("a", (0, 1)),
137 ("b", (1, 3)),
138 ])
139
140 def test_add_window(self):
141 memory_map = MemoryMap(addr_width=16, data_width=8)
142 self.assertEqual(memory_map.add_resource("a", size=1), (0, 1))
143 self.assertEqual(memory_map.add_window(MemoryMap(addr_width=10,
144 data_width=8)),
145 (0x400, 0x800, 1))
146 self.assertEqual(memory_map.add_resource("b", size=1), (0x800, 0x801))
147
148 def test_add_window_sparse(self):
149 memory_map = MemoryMap(addr_width=16, data_width=32)
150 self.assertEqual(memory_map.add_window(MemoryMap(addr_width=10,
151 data_width=8),
152 sparse=True),
153 (0, 0x400, 1))
154
155 def test_add_window_dense(self):
156 memory_map = MemoryMap(addr_width=16, data_width=32)
157 self.assertEqual(memory_map.add_window(MemoryMap(addr_width=10,
158 data_width=8),
159 sparse=False),
160 (0, 0x100, 4))
161
162 def test_add_window_wrong_window(self):
163 memory_map = MemoryMap(addr_width=16, data_width=8)
164 with self.assertRaisesRegex(TypeError,
165 r"Window must be a MemoryMap, not 'a'"):
166 memory_map.add_window("a")
167
168 def test_add_window_wrong_wider(self):
169 memory_map = MemoryMap(addr_width=16, data_width=8)
170 with self.assertRaisesRegex(ValueError,
171 r"Window has data width 16, and cannot be added to a memory "
172 r"map with data width 8"):
173 memory_map.add_window(MemoryMap(addr_width=10, data_width=16))
174
175 def test_add_window_wrong_no_mode(self):
176 memory_map = MemoryMap(addr_width=16, data_width=16)
177 with self.assertRaisesRegex(ValueError,
178 r"Address translation mode must be explicitly specified "
179 r"when adding a window with data width 8 to a memory map "
180 r"with data width 16"):
181 memory_map.add_window(MemoryMap(addr_width=10, data_width=8))
182
183 def test_add_window_wrong_ratio(self):
184 memory_map = MemoryMap(addr_width=16, data_width=16)
185 with self.assertRaisesRegex(ValueError,
186 r"Dense addressing cannot be used because the memory map "
187 r"data width 16 is not an integer multiple of window data "
188 r"width 7"):
189 memory_map.add_window(MemoryMap(addr_width=10, data_width=7),
190 sparse=False)
191
192 def test_add_window_wrong_overlap(self):
193 memory_map = MemoryMap(addr_width=16, data_width=8)
194 memory_map.add_window(MemoryMap(addr_width=10, data_width=8))
195 with self.assertRaisesRegex(ValueError,
196 r"Address range 0x200\.\.0x600 overlaps with window "
197 r"<nmigen_soc\.memory\.MemoryMap object at .+?> "
198 r"at 0x0\.\.0x400"):
199 memory_map.add_window(MemoryMap(addr_width=10, data_width=8),
200 addr=0x200)
201
202 def test_add_window_wrong_twice(self):
203 memory_map = MemoryMap(addr_width=16, data_width=8)
204 window = MemoryMap(addr_width=10, data_width=8)
205 memory_map.add_window(window)
206 with self.assertRaisesRegex(ValueError,
207 r"Window <nmigen_soc\.memory\.MemoryMap object at .+?> is "
208 r"already added at address range 0x0\.\.0x400"):
209 memory_map.add_window(window)
210
211 def test_iter_windows(self):
212 memory_map = MemoryMap(addr_width=16, data_width=16)
213 window_1 = MemoryMap(addr_width=10, data_width=8)
214 memory_map.add_window(window_1, sparse=False)
215 window_2 = MemoryMap(addr_width=12, data_width=16)
216 memory_map.add_window(window_2)
217 self.assertEqual(list(memory_map.windows()), [
218 (window_1, (0, 0x200, 2)),
219 (window_2, (0x1000, 0x2000, 1)),
220 ])
221
222 def test_iter_window_patterns(self):
223 memory_map = MemoryMap(addr_width=16, data_width=16)
224 window_1 = MemoryMap(addr_width=10, data_width=8)
225 memory_map.add_window(window_1, sparse=False)
226 window_2 = MemoryMap(addr_width=12, data_width=16)
227 memory_map.add_window(window_2)
228 self.assertEqual(list(memory_map.window_patterns()), [
229 (window_1, ("000000----------", 2)),
230 (window_2, ("0001------------", 1)),
231 ])
232
233 def test_align_to(self):
234 memory_map = MemoryMap(addr_width=16, data_width=8)
235 self.assertEqual(memory_map.add_resource("a", size=1), (0, 1))
236 self.assertEqual(memory_map.align_to(10), 0x400)
237 self.assertEqual(memory_map.add_resource("b", size=16), (0x400, 0x410))
238
239 def test_align_to_wrong(self):
240 memory_map = MemoryMap(addr_width=16, data_width=8)
241 with self.assertRaisesRegex(ValueError,
242 r"Alignment must be a non-negative integer, not -1"):
243 memory_map.align_to(-1)
244
245
246 class MemoryMapDiscoveryTestCase(unittest.TestCase):
247 def setUp(self):
248 self.root = MemoryMap(addr_width=32, data_width=32)
249 self.res1 = "res1"
250 self.root.add_resource(self.res1, size=16)
251 self.win1 = MemoryMap(addr_width=16, data_width=32)
252 self.root.add_window(self.win1)
253 self.res2 = "res2"
254 self.win1.add_resource(self.res2, size=32)
255 self.res3 = "res3"
256 self.win1.add_resource(self.res3, size=32)
257 self.res4 = "res4"
258 self.root.add_resource(self.res4, size=1)
259 self.win2 = MemoryMap(addr_width=16, data_width=8)
260 self.root.add_window(self.win2, sparse=True)
261 self.res5 = "res5"
262 self.win2.add_resource(self.res5, size=16)
263 self.win3 = MemoryMap(addr_width=16, data_width=8)
264 self.root.add_window(self.win3, sparse=False)
265 self.res6 = "res6"
266 self.win3.add_resource(self.res6, size=16)
267
268 def test_iter_all_resources(self):
269 self.assertEqual(list(self.root.all_resources()), [
270 (self.res1, (0x00000000, 0x00000010, 32)),
271 (self.res2, (0x00010000, 0x00010020, 32)),
272 (self.res3, (0x00010020, 0x00010040, 32)),
273 (self.res4, (0x00020000, 0x00020001, 32)),
274 (self.res5, (0x00030000, 0x00030010, 8)),
275 (self.res6, (0x00040000, 0x00040004, 32)),
276 ])
277
278 def test_find_resource(self):
279 for res, loc in self.root.all_resources():
280 self.assertEqual(self.root.find_resource(res), loc)
281
282 def test_find_resource_wrong(self):
283 with self.assertRaises(KeyError) as error:
284 self.root.find_resource("resNA")
285 self.assertEqual(error.exception.args, ("resNA",))
286
287 def test_decode_address(self):
288 for res, (start, end, width) in self.root.all_resources():
289 self.assertEqual(self.root.decode_address(start), res)
290 self.assertEqual(self.root.decode_address(end - 1), res)
291
292 def test_decode_address_missing(self):
293 self.assertIsNone(self.root.decode_address(0x00000100))