|
1 | 1 | from __future__ import print_function, unicode_literals, absolute_import
|
2 | 2 |
|
3 | 3 | import unittest
|
| 4 | +import io |
4 | 5 | import pyrtl
|
5 | 6 |
|
6 | 7 |
|
@@ -113,10 +114,50 @@ def setUp(self):
|
113 | 114 | pyrtl.reset_working_block()
|
114 | 115 |
|
115 | 116 |
|
| 117 | +paths_print_output = """\ |
| 118 | +From i |
| 119 | + To o |
| 120 | + Path 0 |
| 121 | + tmp5/3W <-- - -- i/2I, tmp4/2W |
| 122 | + tmp6/3W <-- | -- tmp2/3W, tmp5/3W |
| 123 | + o/3O <-- w -- tmp6/3W |
| 124 | + Path 1 |
| 125 | + tmp1/3W <-- c -- tmp0/1W, i/2I |
| 126 | + tmp2/3W <-- & -- tmp1/3W, j/3I |
| 127 | + tmp6/3W <-- | -- tmp2/3W, tmp5/3W |
| 128 | + o/3O <-- w -- tmp6/3W |
| 129 | + To p |
| 130 | + Path 0 |
| 131 | + tmp8/4W <-- c -- tmp7/2W, i/2I |
| 132 | + tmp9/5W <-- - -- k/4I, tmp8/4W |
| 133 | + p/5O <-- w -- tmp9/5W |
| 134 | +From j |
| 135 | + To o |
| 136 | + Path 0 |
| 137 | + tmp2/3W <-- & -- tmp1/3W, j/3I |
| 138 | + tmp6/3W <-- | -- tmp2/3W, tmp5/3W |
| 139 | + o/3O <-- w -- tmp6/3W |
| 140 | + To p |
| 141 | + (No paths) |
| 142 | +From k |
| 143 | + To o |
| 144 | + (No paths) |
| 145 | + To p |
| 146 | + Path 0 |
| 147 | + tmp9/5W <-- - -- k/4I, tmp8/4W |
| 148 | + p/5O <-- w -- tmp9/5W |
| 149 | +""" |
| 150 | + |
| 151 | + |
116 | 152 | class TestPaths(unittest.TestCase):
|
117 | 153 |
|
118 | 154 | def setUp(self):
|
119 | 155 | pyrtl.reset_working_block()
|
| 156 | + # To compare textual consistency, need to make |
| 157 | + # sure we're starting at the same index for all |
| 158 | + # automatically created names. |
| 159 | + pyrtl.wire._reset_wire_indexers() |
| 160 | + pyrtl.memory._reset_memory_indexer() |
120 | 161 |
|
121 | 162 | def test_one_path_to_one_output(self):
|
122 | 163 | a = pyrtl.Input(4, 'a')
|
@@ -181,6 +222,83 @@ def test_subset_of_all_paths(self):
|
181 | 222 | self.assertNotIn(p, paths_from_k) # Because p was not provided as target output
|
182 | 223 | self.assertEqual(len(paths_from_k[o]), 0) # 0 paths from k to o
|
183 | 224 |
|
| 225 | + def test_paths_empty_src_and_dst_equal_with_no_other_logic(self): |
| 226 | + i = pyrtl.Input(4, 'i') |
| 227 | + paths = pyrtl.paths(i, i) |
| 228 | + self.assertEqual(len(paths[i][i]), 0) |
| 229 | + |
| 230 | + def test_paths_with_loop(self): |
| 231 | + r = pyrtl.Register(1, 'r') |
| 232 | + r.next <<= r & ~r |
| 233 | + paths = pyrtl.paths(r, r) |
| 234 | + self.assertEqual(len(paths[r][r]), 2) |
| 235 | + p1, p2 = sorted(paths[r][r], key=lambda p: len(p), reverse=True) |
| 236 | + self.assertEqual(len(p1), 3) |
| 237 | + self.assertEqual(p1[0].op, '~') |
| 238 | + self.assertEqual(p1[1].op, '&') |
| 239 | + self.assertEqual(p1[2].op, 'r') |
| 240 | + self.assertEqual(len(p2), 2) |
| 241 | + self.assertEqual(p2[0].op, '&') |
| 242 | + self.assertEqual(p2[1].op, 'r') |
| 243 | + |
| 244 | + def test_paths_loop_and_input(self): |
| 245 | + i = pyrtl.Input(1, 'i') |
| 246 | + o = pyrtl.Output(1, 'o') |
| 247 | + r = pyrtl.Register(1, 'r') |
| 248 | + r.next <<= i & r |
| 249 | + o <<= r |
| 250 | + paths = pyrtl.paths(r, o) |
| 251 | + self.assertEqual(len(paths[r][o]), 1) |
| 252 | + |
| 253 | + def test_paths_loop_get_arbitrary_inner_wires(self): |
| 254 | + w = pyrtl.WireVector(1, 'w') |
| 255 | + y = w & pyrtl.Const(1) |
| 256 | + w <<= ~y |
| 257 | + paths = pyrtl.paths(w, y) |
| 258 | + self.assertEqual(len(paths[w][y]), 1) |
| 259 | + self.assertEqual(paths[w][y][0][0].op, '&') |
| 260 | + |
| 261 | + def test_paths_no_path_exists(self): |
| 262 | + i = pyrtl.Input(1, 'i') |
| 263 | + o = pyrtl.Output(1, 'o') |
| 264 | + o <<= ~i |
| 265 | + |
| 266 | + w = pyrtl.WireVector(1, 'w') |
| 267 | + y = w & pyrtl.Const(1) |
| 268 | + w <<= ~y |
| 269 | + |
| 270 | + paths = pyrtl.paths(w, o) |
| 271 | + self.assertEqual(len(paths[w][o]), 0) |
| 272 | + |
| 273 | + def test_paths_with_memory(self): |
| 274 | + i = pyrtl.Input(4, 'i') |
| 275 | + o = pyrtl.Output(8, 'o') |
| 276 | + mem = pyrtl.MemBlock(8, 32, 'mem') |
| 277 | + waddr = pyrtl.Input(32, 'waddr') |
| 278 | + raddr = pyrtl.Input(32, 'raddr') |
| 279 | + data = mem[raddr] |
| 280 | + mem[waddr] <<= (i + ~data).truncate(8) |
| 281 | + o <<= data |
| 282 | + |
| 283 | + paths = pyrtl.paths(i, o) |
| 284 | + path = paths[i][o][0] |
| 285 | + self.assertEqual(path[0].op, 'c') |
| 286 | + self.assertEqual(path[1].op, '+') |
| 287 | + self.assertEqual(path[2].op, 's') |
| 288 | + self.assertEqual(path[3].op, '@') |
| 289 | + self.assertEqual(path[4].op, 'm') |
| 290 | + self.assertEqual(path[5].op, 'w') |
| 291 | + |
| 292 | + # TODO Once issue with _MemIndexed lookups is resolved, |
| 293 | + # these should be `data` instead of `data.wire`. |
| 294 | + paths = pyrtl.paths(data.wire, data.wire) |
| 295 | + path = paths[data.wire][data.wire][0] |
| 296 | + self.assertEqual(path[0].op, '~') |
| 297 | + self.assertEqual(path[1].op, '+') |
| 298 | + self.assertEqual(path[2].op, 's') |
| 299 | + self.assertEqual(path[3].op, '@') |
| 300 | + self.assertEqual(path[4].op, 'm') |
| 301 | + |
184 | 302 | def test_all_paths(self):
|
185 | 303 | a, b, c = pyrtl.input_list('a/2 b/4 c/1')
|
186 | 304 | o, p = pyrtl.output_list('o/4 p/2')
|
@@ -218,6 +336,17 @@ def test_all_paths(self):
|
218 | 336 | paths_c_to_p = paths[c][p]
|
219 | 337 | self.assertEqual(len(paths_c_to_p), 1)
|
220 | 338 |
|
| 339 | + def test_pretty_print(self): |
| 340 | + i, j, k = pyrtl.input_list('i/2 j/3 k/4') |
| 341 | + o, p = pyrtl.Output(name='o'), pyrtl.Output(name='p') |
| 342 | + o <<= (i & j) | (i - 1) |
| 343 | + p <<= k - i |
| 344 | + |
| 345 | + paths = pyrtl.paths() |
| 346 | + output = io.StringIO() |
| 347 | + paths.print(file=output) |
| 348 | + self.assertEqual(output.getvalue(), paths_print_output) |
| 349 | + |
221 | 350 |
|
222 | 351 | class TestDistance(unittest.TestCase):
|
223 | 352 |
|
|
0 commit comments