From fb8dc942271471f0f240db09eac82c26d5cad4fe Mon Sep 17 00:00:00 2001
From: Kia <kia@special-circumstanc.es>
Date: Fri, 2 Apr 2021 20:46:26 -0600
Subject: [PATCH] comment AW Memory

---
 rtl_lib/arbitrary_width_memory.py | 35 ++++++++++++++++++++++++++-----
 1 file changed, 30 insertions(+), 5 deletions(-)

diff --git a/rtl_lib/arbitrary_width_memory.py b/rtl_lib/arbitrary_width_memory.py
index 5a13750..e492e55 100644
--- a/rtl_lib/arbitrary_width_memory.py
+++ b/rtl_lib/arbitrary_width_memory.py
@@ -106,38 +106,63 @@ class ArbitraryWidthMemory(Elaboratable):
                         m.d.comb += bus.r_data.eq(last_r_data)
 
                     with m.If(bus.valid_in == 1):
-                        # the index and bit-index computation goes as follows:
+                        # the memory address and bit-index computation goes as follows:
 
-                        # 1) We calculate an unwrapped bit index by multiplying the fake index by the fake data width
+                        # We calculate an unwrapped bit index by multiplying the fake index by the fake data width
                         m.d.comb += unwrapped_bit_index.eq(bus.r_addr * self.fake_data_width)
+
+                        # The memory address is simply the unwrapped bit index divided by the memory data width
+                        # since the memory data width is a power of two, this is a shift!
                         m.d.comb += starting_word.eq(unwrapped_bit_index[self.backing_memory_data_width_bits:])
+
+                        # We say we'll do a fetch at that address:
                         m.d.comb += fetch_address.eq(starting_word)
+
+                        # We start our cut at the unwrapped bit index modulo the memory data width.
+                        # since the memory data width is a power of two, this is the K-least-significant-bits
+                        # of the unwrapped bit index
                         m.d.comb += left_bit_index.eq(unwrapped_bit_index[:self.backing_memory_data_width_bits])
+
+                        # Here's where they start trying to trick you. We need to handle the case where the end of the
+                        # fake word goes beyond a real memory word.
                         m.d.comb += end_bit_pseudo_index.eq(left_bit_index + self.fake_data_width-1)
+
+                        # So here we determine if there's any need for additional memory words:
                         m.d.comb += additional_words.eq(end_bit_pseudo_index[self.backing_memory_data_width_bits:])
 
                         with m.If(additional_words == 0):
+                            # No additional words, calculate which bits we need from the sole word we're fetching:
                             m.d.comb += right_bit_index.eq(end_bit_pseudo_index[:self.backing_memory_data_width_bits])
                         with m.Else():
+                            # Additional words needed, so we fetch the entire remaining part of this word
                             m.d.comb += right_bit_index.eq(self.backing_memory_data_width-1)
+                            # and we register state for the next cycle[s]
                             m.d.sync += next_address.eq(fetch_address + 1)
+                            # rather than keeping track of the next address and the final address,
+                            # we keep track of the current address and how many additional words are left,
+                            # maybe that saves a few LUTs by avoiding wide compares, who knows.
                             m.d.sync += additional_words_regd.eq(additional_words)
                             m.next="ADD"
 
 
                 with m.State("ADD"):
                     # we handle both the full-word fetches and the final (potentially partial word) fetch here
-                    with m.If(additional_words_regd == 1): # special case, we may not have to include the whole word!
+                    with m.If(additional_words_regd == 1):
+                        # We start from zero...
                         m.d.comb += left_bit_index.eq(0)
+                        # But this is the last word, so we may not have to include the whole word!
                         m.d.comb += right_bit_index.eq(end_bit_pseudo_index[:self.backing_memory_data_width_bits])
                         m.d.comb += fetch_address.eq(next_address)
                         m.next = "STALL"
-                    with m.Else():                    # non-special case, fetch the whole word.
+                    with m.Else():
+                        # non-special case, fetch the whole word
                         m.d.comb += left_bit_index.eq(0)
                         m.d.comb += right_bit_index.eq(self.backing_memory_data_width-1)
+                        # and increment the address and decrement the remaining words counter
                         m.d.sync += next_address.eq(next_address + 1)
-                        m.d.comb += fetch_address.eq(next_address)
                         m.d.sync += additional_words_regd.eq(additional_words_regd - 1)
+
+                        m.d.comb += fetch_address.eq(next_address)
                 with m.State("STALL"):
                     m.next="STALL"
             return m
-- 
GitLab