+class DCacheConfig:
+ def __init__(self, LINE_SIZE = 64, # Line size in bytes
+ NUM_LINES = 64, # Number of lines in a set
+ NUM_WAYS = 2, # Number of ways
+ TLB_SET_SIZE = 64, # L1 DTLB entries per set
+ TLB_NUM_WAYS = 2, # L1 DTLB number of sets
+ TLB_LG_PGSZ = 12): # L1 DTLB log_2(page_size)
+ self.LINE_SIZE = LINE_SIZE
+ self.NUM_LINES = NUM_LINES
+ self.NUM_WAYS = NUM_WAYS
+ self.TLB_SET_SIZE = TLB_SET_SIZE
+ self.TLB_NUM_WAYS = TLB_NUM_WAYS
+ self.TLB_LG_PGSZ = TLB_LG_PGSZ
+
+ # BRAM organisation: We never access more than
+ # -- WB_DATA_BITS at a time so to save
+ # -- resources we make the array only that wide, and
+ # -- use consecutive indices to make a cache "line"
+ # --
+ # -- ROW_SIZE is the width in bytes of the BRAM
+ # -- (based on WB, so 64-bits)
+ self.ROW_SIZE = WB_DATA_BITS // 8;
+
+ # ROW_PER_LINE is the number of row (wishbone
+ # transactions) in a line
+ self.ROW_PER_LINE = self.LINE_SIZE // self.ROW_SIZE
+
+ # BRAM_ROWS is the number of rows in BRAM needed
+ # to represent the full dcache
+ self.BRAM_ROWS = self.NUM_LINES * self.ROW_PER_LINE
+
+ print ("ROW_SIZE", self.ROW_SIZE)
+ print ("ROW_PER_LINE", self.ROW_PER_LINE)
+ print ("BRAM_ROWS", self.BRAM_ROWS)
+ print ("NUM_WAYS", self.NUM_WAYS)
+
+ # Bit fields counts in the address
+
+ # REAL_ADDR_BITS is the number of real address
+ # bits that we store
+ self.REAL_ADDR_BITS = 56
+
+ # ROW_BITS is the number of bits to select a row
+ self.ROW_BITS = log2_int(self.BRAM_ROWS)
+
+ # ROW_LINE_BITS is the number of bits to select
+ # a row within a line
+ self.ROW_LINE_BITS = log2_int(self.ROW_PER_LINE)
+
+ # LINE_OFF_BITS is the number of bits for
+ # the offset in a cache line
+ self.LINE_OFF_BITS = log2_int(self.LINE_SIZE)
+
+ # ROW_OFF_BITS is the number of bits for
+ # the offset in a row
+ self.ROW_OFF_BITS = log2_int(self.ROW_SIZE)
+
+ # INDEX_BITS is the number if bits to
+ # select a cache line
+ self.INDEX_BITS = log2_int(self.NUM_LINES)
+
+ # SET_SIZE_BITS is the log base 2 of the set size
+ self.SET_SIZE_BITS = self.LINE_OFF_BITS + self.INDEX_BITS
+
+ # TAG_BITS is the number of bits of
+ # the tag part of the address
+ self.TAG_BITS = self.REAL_ADDR_BITS - self.SET_SIZE_BITS
+
+ # TAG_WIDTH is the width in bits of each way of the tag RAM
+ self.TAG_WIDTH = self.TAG_BITS + 7 - ((self.TAG_BITS + 7) % 8)
+
+ # WAY_BITS is the number of bits to select a way
+ self.WAY_BITS = log2_int(self.NUM_WAYS)
+
+ # Example of layout for 32 lines of 64 bytes:
+ layout = f"""\
+ DCache Layout:
+ |.. -----------------------| REAL_ADDR_BITS ({self.REAL_ADDR_BITS})
+ .. |--------------| SET_SIZE_BITS ({self.SET_SIZE_BITS})
+ .. tag |index| line |
+ .. | row | |
+ .. | |---| | ROW_LINE_BITS ({self.ROW_LINE_BITS})
+ .. | |--- - --| LINE_OFF_BITS ({self.LINE_OFF_BITS})
+ .. | |- --| ROW_OFF_BITS ({self.ROW_OFF_BITS})
+ .. |----- ---| | ROW_BITS ({self.ROW_BITS})
+ .. |-----| | INDEX_BITS ({self.INDEX_BITS})
+ .. --------| | TAG_BITS ({self.TAG_BITS})
+ """
+ print (layout)
+ print ("Dcache TAG %d IDX %d ROW_BITS %d ROFF %d LOFF %d RLB %d" % \
+ (self.TAG_BITS, self.INDEX_BITS, self.ROW_BITS,
+ self.ROW_OFF_BITS, self.LINE_OFF_BITS, self.ROW_LINE_BITS))
+ print ("index @: %d-%d" % (self.LINE_OFF_BITS, self.SET_SIZE_BITS))
+ print ("row @: %d-%d" % (self.LINE_OFF_BITS, self.ROW_OFF_BITS))
+ print ("tag @: %d-%d width %d" % (self.SET_SIZE_BITS,
+ self.REAL_ADDR_BITS, self.TAG_WIDTH))
+
+ self.TAG_RAM_WIDTH = self.TAG_WIDTH * self.NUM_WAYS
+
+ print ("TAG_RAM_WIDTH", self.TAG_RAM_WIDTH)
+ print (" TAG_WIDTH", self.TAG_WIDTH)
+ print (" NUM_WAYS", self.NUM_WAYS)
+ print (" NUM_LINES", self.NUM_LINES)
+
+ # L1 TLB
+ self.TLB_SET_BITS = log2_int(self.TLB_SET_SIZE)
+ self.TLB_WAY_BITS = log2_int(self.TLB_NUM_WAYS)
+ self.TLB_EA_TAG_BITS = 64 - (self.TLB_LG_PGSZ + self.TLB_SET_BITS)
+ self.TLB_TAG_WAY_BITS = self.TLB_NUM_WAYS * self.TLB_EA_TAG_BITS
+ self.TLB_PTE_BITS = 64
+ self.TLB_PTE_WAY_BITS = self.TLB_NUM_WAYS * self.TLB_PTE_BITS;
+
+ assert (self.LINE_SIZE % self.ROW_SIZE) == 0, \
+ "LINE_SIZE not multiple of ROW_SIZE"
+ assert ispow2(self.LINE_SIZE), "LINE_SIZE not power of 2"
+ assert ispow2(self.NUM_LINES), "NUM_LINES not power of 2"
+ assert ispow2(self.ROW_PER_LINE), "ROW_PER_LINE not power of 2"
+ assert self.ROW_BITS == \
+ (self.INDEX_BITS + self.ROW_LINE_BITS), \
+ "geometry bits don't add up"
+ assert (self.LINE_OFF_BITS == \
+ self.ROW_OFF_BITS + self.ROW_LINE_BITS), \
+ "geometry bits don't add up"
+ assert self.REAL_ADDR_BITS == \
+ (self.TAG_BITS + self.INDEX_BITS + self.LINE_OFF_BITS), \
+ "geometry bits don't add up"
+ assert self.REAL_ADDR_BITS == \
+ (self.TAG_BITS + self.ROW_BITS + self.ROW_OFF_BITS), \
+ "geometry bits don't add up"
+ assert 64 == WB_DATA_BITS, \
+ "Can't yet handle wb width that isn't 64-bits"
+ assert self.SET_SIZE_BITS <= self.TLB_LG_PGSZ, \
+ "Set indexed by virtual address"
+
+ def CacheTagArray(self):
+ return Array(Signal(self.TAG_RAM_WIDTH, name="tag%d" % x) \
+ for x in range(self.NUM_LINES))
+
+ def CacheValidsArray(self):
+ return Array(Signal(self.NUM_WAYS, name="tag_valids%d" % x)
+ for x in range(self.NUM_LINES))
+
+ def RowPerLineValidArray(self):
+ return Array(Signal(name="rows_valid%d" % x) \
+ for x in range(self.ROW_PER_LINE))
+
+ def TLBHit(self, name):
+ return Record([('valid', 1),
+ ('way', self.TLB_WAY_BITS)], name=name)
+
+ def TLBTagEAArray(self):
+ return Array(Signal(self.TLB_EA_TAG_BITS, name="tlbtagea%d" % x) \
+ for x in range (self.TLB_NUM_WAYS))
+
+ def TLBRecord(self, name):
+ tlb_layout = [('valid', self.TLB_NUM_WAYS),
+ ('tag', self.TLB_TAG_WAY_BITS),
+ ('pte', self.TLB_PTE_WAY_BITS)
+ ]
+ return Record(tlb_layout, name=name)
+
+ def TLBValidArray(self):
+ return Array(Signal(self.TLB_NUM_WAYS, name="tlb_valid%d" % x)
+ for x in range(self.TLB_SET_SIZE))
+
+ def HitWaySet(self):
+ return Array(Signal(self.WAY_BITS, name="hitway_%d" % x) \
+ for x in range(self.TLB_NUM_WAYS))
+
+ # Cache RAM interface
+ def CacheRamOut(self):
+ return Array(Signal(self.WB_DATA_BITS, name="cache_out%d" % x) \
+ for x in range(self.NUM_WAYS))
+
+ # PLRU output interface
+ def PLRUOut(self):
+ return Array(Signal(self.WAY_BITS, name="plru_out%d" % x) \
+ for x in range(self.NUM_LINES))
+
+ # TLB PLRU output interface
+ def TLBPLRUOut(self):
+ return Array(Signal(self.TLB_WAY_BITS, name="tlbplru_out%d" % x) \
+ for x in range(self.TLB_SET_SIZE))
+
+ # Helper functions to decode incoming requests
+ #
+ # Return the cache line index (tag index) for an address
+ def get_index(self, addr):
+ return addr[self.LINE_OFF_BITS:self.SET_SIZE_BITS]
+
+ # Return the cache row index (data memory) for an address
+ def get_row(self, addr):
+ return addr[self.ROW_OFF_BITS:self.SET_SIZE_BITS]