add option to set small cache sizes in
[soc.git] / src / soc / experiment / icache.py
index 8e457be57a8083d30951d109cc4d47efca95edc0..ff45332d8fd9a5460464468fcefbffd9e808306f 100644 (file)
@@ -72,11 +72,13 @@ SIM            = 0
 LOG_LENGTH     = 0
 
 class ICacheConfig:
-    def __init__(self, LINE_SIZE     = 64,
+    def __init__(self, XLEN          = 64,
+                       LINE_SIZE     = 64,
                        NUM_LINES     = 64,  # Number of lines in a set
                        NUM_WAYS      = 2,  # Number of ways
                        TLB_SIZE      = 64,  # L1 ITLB number of entries
                        TLB_LG_PGSZ   = 12): # L1 ITLB log_2(page_size)
+        self.XLEN           = XLEN
         self.LINE_SIZE      = LINE_SIZE
         self.NUM_LINES      = NUM_LINES
         self.NUM_WAYS       = NUM_WAYS
@@ -91,7 +93,7 @@ class ICacheConfig:
         # (based on WB, so 64-bits)
         self.ROW_SIZE       = WB_DATA_BITS // 8
         # Number of real address bits that we store
-        self.REAL_ADDR_BITS = 56
+        self.REAL_ADDR_BITS = XLEN-8 # 56 for XLEN=64
 
         self.ROW_SIZE_BITS  = self.ROW_SIZE * 8
         # ROW_PER_LINE is the number of row (wishbone) transactions in a line
@@ -129,9 +131,10 @@ class ICacheConfig:
 
         # L1 ITLB
         self.TL_BITS        = log2_int(self.TLB_SIZE)
-        self.TLB_EA_TAG_BITS = 64 - (self.TLB_LG_PGSZ + self.TL_BITS)
-        self.TLB_PTE_BITS    = 64
+        self.TLB_EA_TAG_BITS = XLEN - (self.TLB_LG_PGSZ + self.TL_BITS)
+        self.TLB_PTE_BITS    = XLEN
 
+        print("self.XLEN            =", self.XLEN)
         print("self.BRAM_ROWS       =", self.BRAM_ROWS)
         print("self.INDEX_BITS      =", self.INDEX_BITS)
         print("self.INSN_BITS       =", self.INSN_BITS)
@@ -159,6 +162,7 @@ class ICacheConfig:
         print("self.TLB_PTE_BITS    =", self.TLB_PTE_BITS)
         print("self.TLB_SIZE        =", self.TLB_SIZE)
         print("self.WAY_BITS        =", self.WAY_BITS)
+        print()
 
         assert self.LINE_SIZE % self.ROW_SIZE == 0
         assert ispow2(self.LINE_SIZE), "self.LINE_SIZE not power of 2"
@@ -331,18 +335,33 @@ class ICache(FetchUnitInterface, Elaboratable, ICacheConfig):
         # use FetchUnitInterface, helps keep some unit tests running
         self.use_fetch_iface = False
 
-        # test if microwatt compatibility is to be enabled
+        # test if small cache to be enabled
+        self.small_cache = (hasattr(pspec, "small_cache") and
+                                 (pspec.small_cache == True))
+        # test if microwatt compatibility to be enabled
         self.microwatt_compat = (hasattr(pspec, "microwatt_compat") and
                                  (pspec.microwatt_compat == True))
 
+        XLEN = pspec.XLEN
+        LINE_SIZE = 64
+        TLB_SIZE = 16
+        NUM_LINES = 16
+        NUM_WAYS = 2
+        if self.small_cache:
+            # reduce way sizes and num lines to ridiculously small
+            NUM_LINES = 2
+            NUM_WAYS = 1
+            TLB_SIZE = 2
         if self.microwatt_compat:
-            # reduce way sizes and num lines
-            ICacheConfig.__init__(self, NUM_LINES = 4,
-                                        NUM_WAYS = 1,
-                                        TLB_SIZE=16 # needs device-tree update
-                                 )
-        else:
-            ICacheConfig.__init__(self)
+            # reduce way sizes
+            NUM_WAYS = 1
+
+        ICacheConfig.__init__(self, LINE_SIZE=LINE_SIZE,
+                                    XLEN=XLEN,
+                                    NUM_LINES = NUM_LINES,
+                                    NUM_WAYS = NUM_WAYS,
+                                    TLB_SIZE=TLB_SIZE
+                             )
 
     def use_fetch_interface(self):
         self.use_fetch_iface = True
@@ -411,7 +430,8 @@ class ICache(FetchUnitInterface, Elaboratable, ICacheConfig):
             return
 
 
-        m.submodules.plrus = plru = PLRUs(self.NUM_LINES, self.WAY_BITS)
+        m.submodules.plrus = plru = PLRUs("itag", self.NUM_LINES,
+                                                  self.WAY_BITS)
         comb += plru.way.eq(r.hit_way)
         comb += plru.valid.eq(r.hit_valid)
         comb += plru.index.eq(self.get_index(r.hit_nia))
@@ -687,29 +707,20 @@ class ICache(FetchUnitInterface, Elaboratable, ICacheConfig):
         sync += r.state.eq(State.WAIT_ACK)
 
     def icache_miss_wait_ack(self, m, r, replace_way, inval_in,
-                             cache_valids, stbs_done):
+                             cache_valids):
         comb = m.d.comb
         sync = m.d.sync
 
         bus = self.bus
 
-        # Requests are all sent if stb is 0
-        stbs_zero = Signal()
-        comb += stbs_zero.eq(r.wb.stb == 0)
-        comb += stbs_done.eq(stbs_zero)
-
         # If we are still sending requests, was one accepted?
-        with m.If(~bus.stall & ~stbs_zero):
-            # That was the last word? We are done sending.
-            # Clear stb and set stbs_done so we can handle
-            # an eventual last ack on the same cycle.
+        with m.If(~bus.stall & r.wb.stb):
+            # That was the last word? We are done sending.  Clear stb
             with m.If(self.is_last_row_addr(r.req_adr, r.end_row_ix)):
                 sync += Display("IS_LAST_ROW_ADDR r.wb.addr:%x "
-                         "r.end_row_ix:%x r.wb.stb:%x stbs_zero:%x "
-                         "stbs_done:%x", r.wb.adr, r.end_row_ix,
-                         r.wb.stb, stbs_zero, stbs_done)
+                         "r.end_row_ix:%x r.wb.stb:%x",
+                         r.wb.adr, r.end_row_ix, r.wb.stb)
                 sync += r.wb.stb.eq(0)
-                comb += stbs_done.eq(1)
 
             # Calculate the next row address
             rarange = Signal(self.LINE_OFF_BITS - self.ROW_OFF_BITS)
@@ -717,19 +728,17 @@ class ICache(FetchUnitInterface, Elaboratable, ICacheConfig):
                                          self.LINE_OFF_BITS] + 1)
             sync += r.req_adr[self.ROW_OFF_BITS:self.LINE_OFF_BITS].eq(rarange)
             sync += Display("RARANGE r.req_adr:%x rarange:%x "
-                            "stbs_zero:%x stbs_done:%x",
-                            r.req_adr, rarange, stbs_zero, stbs_done)
+                            "r.wb.stb:%x",
+                            r.req_adr, rarange, r.wb.stb)
 
         # Incoming acks processing
         with m.If(bus.ack):
-            sync += Display("WB_IN_ACK data:%x stbs_zero:%x "
-                            "stbs_done:%x",
-                            bus.dat_r, stbs_zero, stbs_done)
+            sync += Display("WB_IN_ACK data:%x", bus.dat_r)
 
             sync += r.rows_valid[r.store_row % self.ROW_PER_LINE].eq(1)
 
             # Check for completion
-            with m.If(stbs_done & self.is_last_row(r.store_row, r.end_row_ix)):
+            with m.If(self.is_last_row(r.store_row, r.end_row_ix)):
                 # Complete wishbone cycle
                 sync += r.wb.cyc.eq(0)
                 # be nice, clear addr
@@ -756,8 +765,6 @@ class ICache(FetchUnitInterface, Elaboratable, ICacheConfig):
         stall_in, flush_in = self.stall_in, self.flush_in
         inval_in           = self.inval_in
 
-        stbs_done = Signal()
-
         comb += r.wb.sel.eq(-1)
         comb += r.wb.adr.eq(r.req_adr[3:])
 
@@ -781,7 +788,7 @@ class ICache(FetchUnitInterface, Elaboratable, ICacheConfig):
                                              cache_valids)
 
                 self.icache_miss_wait_ack(m, r, replace_way, inval_in,
-                                          cache_valids, stbs_done)
+                                          cache_valids)
 
         # TLB miss and protection fault processing
         with m.If(flush_in | m_in.tlbld):
@@ -1023,6 +1030,7 @@ def test_icache(mem):
     pspec = TestMemPspec(addr_wid=32,
                          mask_wid=8,
                          reg_wid=64,
+                         XLEN=32,
                          )
     dut    = ICache(pspec)
 
@@ -1057,6 +1065,7 @@ if __name__ == '__main__':
     from soc.config.test.test_loadstore import TestMemPspec
     pspec = TestMemPspec(addr_wid=64,
                          mask_wid=8,
+                         XLEN=32,
                          reg_wid=64,
                          )
     dut = ICache(pspec)