Merge branch 'master' of https://git.libre-riscv.org/git/soc
[soc.git] / src / scoreboard / addr_match.py
index 657f95b68851b4df7a40eec031694e2246c3ea49..9d8e08e4542bd6338442101f2ed0a1c380a9284e 100644 (file)
@@ -19,12 +19,21 @@ without using expensive comparators) probably the best way to do so would
 be to turn the last 16 bits into a byte-level bitmap.  LD/ST on a byte
 would have 1 of the 16 bits set.  LD/ST on a DWORD would have 8 of the 16
 bits set (offset if the LD/ST was misaligned).  TODO.
+
+Notes:
+
+> I have used bits <11:6> as they are not translated (4KB pages)
+> and larger than a cache line (64 bytes).
+> I have used bits <11:4> when the L1 cache was QuadW sized and
+> the L2 cache was Line sized.
 """
 
 from nmigen.compat.sim import run_simulation
 from nmigen.cli import verilog, rtlil
 from nmigen import Module, Signal, Const, Array, Cat, Elaboratable
 
+from nmutil.latch import latchregister, SRLatch
+
 
 class PartialAddrMatch(Elaboratable):
     """A partial address matcher
@@ -35,26 +44,35 @@ class PartialAddrMatch(Elaboratable):
         # inputs
         self.addrs_i = Array(Signal(bitwid, name="addr") for i in range(n_adr))
         self.addr_we_i = Signal(n_adr) # write-enable for incoming address
-        self.addr_en_i = Signal(n_adr) # address activated (0 == ignore)
+        self.addr_en_i = Signal(n_adr) # address latched in
+        self.addr_rs_i = Signal(n_adr) # address deactivated
 
         # output
-        self.addr_match_o = Signal(n_adr)
+        self.addr_nomatch_o = Signal(n_adr, name="nomatch_o")
+        self.addr_nomatch_a_o = Array(Signal(n_adr, name="nomatch_array_o") \
+                                  for i in range(n_adr))
 
     def elaborate(self, platform):
         m = Module()
+        return self._elaborate(m, platform)
+
+    def _elaborate(self, m, platform):
         comb = m.d.comb
         sync = m.d.sync
 
+        m.submodules.l = l = SRLatch(llen=self.n_adr, sync=False)
         addrs_r = Array(Signal(self.bitwid, "a_r") for i in range(self.n_adr))
-        addr_en_r = Signal(self.n_adr)
+
+        # latch set/reset
+        comb += l.s.eq(self.addr_en_i)
+        comb += l.r.eq(self.addr_rs_i)
 
         # copy in addresses (and "enable" signals)
         for i in range(self.n_adr):
-            with m.If(self.addr_we_i[i]):
-                sync += addrs_r[i].eq(self.addrs_i[i])
-                sync += addr_en_r[i].eq(self.addr_en_i[i])
+            latchregister(m, self.addrs_i[i], addrs_r[i], l.q[i])
 
         # is there a clash, yes/no
+        matchgrp = []
         for i in range(self.n_adr):
             match = []
             for j in range(self.n_adr):
@@ -62,7 +80,9 @@ class PartialAddrMatch(Elaboratable):
                     match.append(Const(0)) # don't match against self!
                 else:
                     match.append(addrs_r[i] == addrs_r[j])
-            comb += self.addr_match_o.eq(Cat(*match).bool() & addr_en_r)
+            comb += self.addr_nomatch_a_o[i].eq(~Cat(*match) & l.q)
+            matchgrp.append(self.addr_nomatch_a_o[i] == l.q)
+        comb += self.addr_nomatch_o.eq(Cat(*matchgrp) & l.q)
             
         return m
 
@@ -70,7 +90,8 @@ class PartialAddrMatch(Elaboratable):
         yield from self.addrs_i
         yield self.addr_we_i
         yield self.addr_en_i
-        yield self.addr_match_o
+        yield from self.addr_nomatch_a_o
+        yield self.addr_nomatch_o
 
     def ports(self):
         return list(self)