From 921d740daf59cc4e286cce772cff12985b207713 Mon Sep 17 00:00:00 2001 From: whitequark Date: Sat, 26 Oct 2019 02:52:49 +0000 Subject: [PATCH] memory: add Memory.window_patterns(), to simplify decoders. --- nmigen_soc/csr/bus.py | 13 ++++--------- nmigen_soc/memory.py | 17 +++++++++++++++++ nmigen_soc/test/test_memory.py | 11 +++++++++++ 3 files changed, 32 insertions(+), 9 deletions(-) diff --git a/nmigen_soc/csr/bus.py b/nmigen_soc/csr/bus.py index 31a237d..e0c0b92 100644 --- a/nmigen_soc/csr/bus.py +++ b/nmigen_soc/csr/bus.py @@ -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 diff --git a/nmigen_soc/memory.py b/nmigen_soc/memory.py index c7214e0..d50dbb6 100644 --- a/nmigen_soc/memory.py +++ b/nmigen_soc/memory.py @@ -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 diff --git a/nmigen_soc/test/test_memory.py b/nmigen_soc/test/test_memory.py index bc5a1ce..2461f9b 100644 --- a/nmigen_soc/test/test_memory.py +++ b/nmigen_soc/test/test_memory.py @@ -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)) -- 2.30.2