diff --git a/bin/CacheSim.py b/bin/CacheSim.py index d17e1d9c..44b773c5 100755 --- a/bin/CacheSim.py +++ b/bin/CacheSim.py @@ -2,14 +2,14 @@ # Authors: Limnanthes Serafini (lserafini@hmc.edu) and Alec Vercruysse (avercruysse@hmc.edu) # TODO: add better (more formal?) attribution, commenting, improve output -# maybe TODO: edit __repr__ of the classes? -# it would also be nice if we could log evictions in Wally's caches import sys import math import argparse import os +debug = True + class CacheLine: def __init__(self): self.tag = 0 @@ -62,13 +62,14 @@ class Cache: self.pLRU.append([0]*(self.numways-1)) def splitaddr(self, addr): - # no need for offset in the sim - setnum = (addr >> self.offsetlen) - ((addr >> (self.setlen + self.offsetlen)) << self.setlen) - tag = addr >> (self.setlen + self.offsetlen) - return tag, setnum + # no need for offset in the sim, but it's here for debug + tag = addr >> (self.setlen + self.offsetlen) & int('1'*self.taglen, 2) + setnum = (addr >> self.offsetlen) & int('1'*self.setlen, 2) + offset = addr & int('1'*self.offsetlen, 2) + return tag, setnum, offset def cacheaccess(self, addr, write=False): - tag, setnum = self.splitaddr(addr) + tag, setnum, _ = self.splitaddr(addr) # check our ways to see if we have a hit for waynum in range(self.numways): @@ -96,6 +97,7 @@ class Cache: # we need to evict. Select a victim and overwrite. victim = self.getvictimway(setnum) line = self.ways[victim][setnum] + prevdirty = line.dirty #print("Evicting tag", line.tag, "from set", setnum, "way", victim) #print("replacing with", tag) line.tag = tag @@ -104,8 +106,8 @@ class Cache: line.dirty = True else: line.dirty = False - self.update_pLRU(waynum, setnum) - return 'M' # update this to 'E' if we get evictions loggable + self.update_pLRU(victim, setnum) + return 'D' if prevdirty else 'E' def update_pLRU(self, waynum, setnum): if self.numways == 1: @@ -166,32 +168,42 @@ if __name__ == "__main__": args = parser.parse_args() cache = Cache(args.numlines, args.numways, args.addrlen, args.taglen) + + extfile = os.path.expanduser(args.file) - # go looking in the sim directory for the file if it doesn't exist - # if not os.path.isfile(args.file): - # args.file = os.path.expanduser("~/cvw/sim/" + args.file) - - with open(args.file, "r") as f: + with open(extfile, "r") as f: for ln in f: ln = ln.strip() lninfo = ln.split() if len(lninfo) < 3: #non-address line - if lninfo[0] == 'BEGIN': + if len(lninfo) > 0 and (lninfo[0] == 'BEGIN' or lninfo[0] == 'TRAIN'): + #currently BEGIN and END traces aren't being recorded correctly + #trying TRAIN clears instead cache.invalidate() # a new test is starting, so 'empty' the cache cache.clear_pLRU() + if debug: + print("new test?") else: - if lninfo[1] == 'F': - cache.flush() - else: - addr = int(lninfo[0], 16) - result = cache.cacheaccess(addr, lninfo[1] == 'W') # add support for A - #tag, setnum = cache.splitaddr(addr) - #print(hex(tag), hex(setnum), lninfo[2], result) - if not result == lninfo[2]: - print("Result mismatch at address", lninfo[0], ". Wally:", lninfo[2],", Sim:", result) - #print() - - #print(cache) + if len(lninfo[0]) >= (cache.addrlen/4): #more hacking around the logging issues + if lninfo[1] == 'F': + cache.flush() + if debug: + print("flush") + elif lninfo[1] == 'I': + cache.invalidate() + if debug: + print("inval") + else: + addr = int(lninfo[0], 16) + iswrite = lninfo[1] == 'W' or lninfo[1] == 'A' + result = cache.cacheaccess(addr, iswrite) + if debug: + tag, setnum, offset = cache.splitaddr(addr) + print(hex(addr), hex(tag), hex(setnum), hex(offset), lninfo[2], result) + if not result == lninfo[2]: + print("Result mismatch at address", lninfo[0], ". Wally:", lninfo[2],", Sim:", result) + if debug: + break # breaking after the first mismatch makes for easier debugging diff --git a/testbench/testbench.sv b/testbench/testbench.sv index 2bc3622c..00a43560 100644 --- a/testbench/testbench.sv +++ b/testbench/testbench.sv @@ -480,7 +480,7 @@ logic [3:0] dummy; assign EndSample = DCacheFlushStart & ~DCacheFlushDone; flop #(1) BeginReg(clk, StartSampleFirst, BeginDelayed); - assign Begin = StartSampleFirst & ~ BeginDelayed; + assign Begin = StartSampleFirst & ~BeginDelayed; end @@ -555,7 +555,7 @@ logic [3:0] dummy; end - if (`ICACHE_SUPPORTED && `I_CACHE_ADDR_LOGGER) begin +if (`ICACHE_SUPPORTED && `I_CACHE_ADDR_LOGGER) begin : ICacheLogger int file; string LogFile; logic resetD, resetEdge; @@ -568,26 +568,42 @@ end file = $fopen(LogFile, "w"); $fwrite(file, "BEGIN %s\n", memfilename); end - string HitMissString; - assign HitMissString = dut.core.ifu.bus.icache.icache.CacheHit ? "H" : "M"; + string AccessTypeString, HitMissString; + assign HitMissString = dut.core.ifu.bus.icache.icache.CacheHit ? "H" : + dut.core.ifu.bus.icache.icache.vict.cacheLRU.AllValid ? "E" : "M"; + assign AccessTypeString = dut.core.ifu.InvalidateICacheM ? "I" : "R"; always @(posedge clk) begin if(resetEdge) $fwrite(file, "TRAIN\n"); if(Begin) $fwrite(file, "BEGIN %s\n", memfilename); if(Enable) begin // only log i cache reads - $fwrite(file, "%h R %s\n", dut.core.ifu.PCPF, HitMissString); + $fwrite(file, "%h %s %s\n", dut.core.ifu.PCPF, AccessTypeString, HitMissString); end if(EndSample) $fwrite(file, "END %s\n", memfilename); end end - if (`DCACHE_SUPPORTED && `D_CACHE_ADDR_LOGGER) begin + // old version + if (`DCACHE_SUPPORTED && `D_CACHE_ADDR_LOGGER) begin : DCacheLogger int file; string LogFile; logic resetD, resetEdge; - string HitMissString; + logic Enabled; + string AccessTypeString, HitMissString; + flop #(1) ResetDReg(clk, reset, resetD); assign resetEdge = ~reset & resetD; - assign HitMissString = dut.core.lsu.bus.dcache.dcache.CacheHit ? "H" : "M"; + assign HitMissString = dut.core.lsu.bus.dcache.dcache.CacheHit ? "H" : + (!dut.core.lsu.bus.dcache.dcache.vict.cacheLRU.AllValid) ? "M" : + dut.core.lsu.bus.dcache.dcache.LineDirty ? "D" : "E"; + assign AccessTypeString = dut.core.lsu.bus.dcache.FlushDCache ? "F" : + dut.core.lsu.bus.dcache.CacheAtomicM[1] ? "A" : + dut.core.lsu.bus.dcache.CacheRWM == 2'b10 ? "R" : + dut.core.lsu.bus.dcache.CacheRWM == 2'b01 ? "W" : + "NULL"; + assign Enabled = (dut.core.lsu.bus.dcache.dcache.cachefsm.CurrState == 0) & + ~dut.core.lsu.bus.dcache.dcache.cachefsm.FlushStage & + (AccessTypeString != "NULL"); + initial begin LogFile = $psprintf("DCache.log"); file = $fopen(LogFile, "w"); @@ -596,16 +612,8 @@ end always @(posedge clk) begin if(resetEdge) $fwrite(file, "TRAIN\n"); if(Begin) $fwrite(file, "BEGIN %s\n", memfilename); - if(~dut.core.StallW & ~dut.core.FlushW & dut.core.InstrValidM) begin - if(dut.core.lsu.bus.dcache.CacheRWM == 2'b10) begin - $fwrite(file, "%h R %s\n", dut.core.lsu.PAdrM, HitMissString); - end else if (dut.core.lsu.bus.dcache.CacheRWM == 2'b01) begin - $fwrite(file, "%h W %s\n", dut.core.lsu.PAdrM, HitMissString); - end else if (dut.core.lsu.bus.dcache.CacheAtomicM[1] == 1'b1) begin // *** This may change - $fwrite(file, "%h A %s\n", dut.core.lsu.PAdrM, HitMissString); - end else if (dut.core.lsu.bus.dcache.FlushDCache) begin - $fwrite(file, "%h F %s\n", dut.core.lsu.PAdrM, HitMissString); - end + if(Enabled) begin + $fwrite(file, "%h %s %s\n", dut.core.lsu.PAdrM, AccessTypeString, HitMissString); end if(EndSample) $fwrite(file, "END %s\n", memfilename); end diff --git a/tests/custom/cacheSimTest/CacheSimTest.py b/tests/custom/cacheSimTest/CacheSimTest.py new file mode 100755 index 00000000..f78e7fc0 --- /dev/null +++ b/tests/custom/cacheSimTest/CacheSimTest.py @@ -0,0 +1,64 @@ +#!/usr/bin/env python3 + +# Authors: Limnanthes Serafini (lserafini@hmc.edu) and Alec Vercruysse (avercruysse@hmc.edu) + +import sys +import os + +sys.path.append(os.path.expanduser("~/cvw/bin")) +import CacheSim as cs + +if __name__ == "__main__": + cache = cs.Cache(16, 4, 16, 8) + # 0xABCD -> tag: AB, set: C, offset: D + + #address split checking + assert (cache.splitaddr(0x1234) == (0x12,0x3,0x4)) + assert (cache.splitaddr(0x2638) == (0x26,0x3,0x8)) + assert (cache.splitaddr(0xA3E6) == (0xA3,0xE,0x6)) + + #insert way 0 set C tag AB + assert (cache.cacheaccess(0xABCD) == 'M') + assert (cache.ways[0][0xC].tag == 0xAB) + assert (cache.cacheaccess(0xABCD) == 'H') + assert (cache.pLRU[0xC] == [1,1,0]) + + #make way 0 set C dirty + assert (cache.cacheaccess(0xABCD, True) == 'H') + + #insert way 1 set C tag AC + assert (cache.cacheaccess(0xACCD) == 'M') + assert (cache.ways[1][0xC].tag == 0xAC) + assert (cache.pLRU[0xC] == [1,0,0]) + + #insert way 2 set C tag AD + assert (cache.cacheaccess(0xADCD) == 'M') + assert (cache.ways[2][0xC].tag == 0xAD) + assert (cache.pLRU[0xC] == [0,0,1]) + + #insert way 3 set C tag AE + assert (cache.cacheaccess(0xAECD) == 'M') + assert (cache.ways[3][0xC].tag == 0xAE) + assert (cache.pLRU[0xC] == [0,0,0]) + + #misc hit and pLRU checking + assert (cache.cacheaccess(0xABCD) == 'H') + assert (cache.pLRU[0xC] == [1,1,0]) + assert (cache.cacheaccess(0xADCD) == 'H') + assert (cache.pLRU[0xC] == [0,1,1]) + + #evict way 1, now set C has tag AF + assert (cache.cacheaccess(0xAFCD) == 'E') + assert (cache.ways[1][0xC].tag == 0xAF) + assert (cache.pLRU[0xC] == [1,0,1]) + + #evict way 3, now set C has tag AC + assert (cache.cacheaccess(0xACCD) == 'E') + assert (cache.ways[3][0xC].tag == 0xAC) + assert (cache.pLRU[0xC] == [0,0,0]) + + #evict way 0, now set C has tag EA + #this line was dirty, so there was a wb + assert (cache.cacheaccess(0xEAC2) == 'D') + assert (cache.ways[0][0xC].tag == 0xEA) + assert (cache.pLRU[0xC] == [1,1,0]) \ No newline at end of file