memory: add Memory.window_patterns(), to simplify decoders.
authorwhitequark <whitequark@whitequark.org>
Sat, 26 Oct 2019 02:52:49 +0000 (02:52 +0000)
committerwhitequark <whitequark@whitequark.org>
Sat, 26 Oct 2019 02:54:13 +0000 (02:54 +0000)
nmigen_soc/csr/bus.py
nmigen_soc/memory.py
nmigen_soc/test/test_memory.py

index 31a237dee745382aba9094c1ff45ed0fe2a296e6..e0c0b929db420f1de688bd87e264ff5ec1e78664 100644 (file)
@@ -330,14 +330,8 @@ class Decoder(Elaboratable):
             raise ValueError("Subordinate bus has data width {}, which is not the same as "
                              "multiplexer data width {}"
                              .format(sub_bus.data_width, self.bus.data_width))
-
-        start, end, ratio = window_range = self._map.add_window(sub_bus.memory_map, addr=addr)
-        assert ratio == 1
-        pattern = "{:0{}b}{}".format(start >> sub_bus.addr_width,
-                                     self.bus.addr_width - sub_bus.addr_width,
-                                     "-" * sub_bus.addr_width)
-        self._subs[pattern] = sub_bus
-        return window_range
+        self._subs[sub_bus.memory_map] = sub_bus
+        return self._map.add_window(sub_bus.memory_map, addr=addr)
 
     def elaborate(self, platform):
         m = Module()
@@ -346,7 +340,8 @@ class Decoder(Elaboratable):
         r_data_fanin = 0
 
         with m.Switch(self.bus.addr):
-            for sub_pat, sub_bus in self._subs.items():
+            for sub_map, sub_pat in self._map.window_patterns():
+                sub_bus = self._subs[sub_map]
                 m.d.comb += sub_bus.addr.eq(self.bus.addr[:sub_bus.addr_width])
 
                 # The CSR bus interface is defined to output zero when idle, allowing us to avoid
index c7214e0e4eed34a00f5ec56beda101c2d4e38eee..d50dbb69f22ca2ae23d5b81e226a2ff6be6256fb 100644 (file)
@@ -321,6 +321,23 @@ class MemoryMap:
         for window, window_range in self._windows.items():
             yield window, (window_range.start, window_range.stop, window_range.step)
 
+    def window_patterns(self):
+        """Iterate local windows and patterns that match their address ranges.
+
+        Non-recursively iterate windows in ascending order of their address.
+
+        Yield values
+        ------------
+        A tuple ``window, pattern`` describing the address range assigned to the window.
+        ``pattern`` is a ``self.addr_width`` wide pattern that may be used in ``Case`` or ``match``
+        to determine if an address signal is within the address range of ``window``.
+        """
+        for window, window_range in self._windows.items():
+            pattern = "{:0{}b}{}".format(window_range.start >> window.addr_width,
+                                         self.addr_width - window.addr_width,
+                                         "-" * window.addr_width)
+            yield window, pattern
+
     @staticmethod
     def _translate(start, end, width, window, window_range):
         assert (end - start) % window_range.step == 0
index bc5a1ceefe873231e2834104a124da8da7a37097..2461f9bcdf2e5daa87136129a4ddc8d8d3426569 100644 (file)
@@ -209,6 +209,17 @@ class MemoryMapTestCase(unittest.TestCase):
             (window_2, (0x1000, 0x2000, 1)),
         ])
 
+    def test_iter_window_patterns(self):
+        memory_map = MemoryMap(addr_width=16, data_width=16)
+        window_1 = MemoryMap(addr_width=10, data_width=8)
+        memory_map.add_window(window_1, sparse=False)
+        window_2 = MemoryMap(addr_width=12, data_width=16)
+        memory_map.add_window(window_2)
+        self.assertEqual(list(memory_map.window_patterns()), [
+            (window_1, "000000----------"),
+            (window_2, "0001------------"),
+        ])
+
     def test_align_to(self):
         memory_map = MemoryMap(addr_width=16, data_width=8)
         self.assertEqual(memory_map.add_resource("a", size=1), (0, 1))