diff --git a/sim/GetLineNum.do b/sim/GetLineNum.do new file mode 100644 index 00000000..4d38d912 --- /dev/null +++ b/sim/GetLineNum.do @@ -0,0 +1,18 @@ +# Alec Vercruysse +# 2023-04-12 +# Note that the target string is regex, and needs to be double-escaped. +# e.g. to match a (, you need \\(. +proc GetLineNum {fname target} { + set f [open $fname] + set linectr 1 + while {[gets $f line] != -1} { + if {[regexp $target $line]} { + close $f + return $linectr + } + incr linectr + } + close $f + return -code error \ + "target string not found" +} diff --git a/sim/coverage-exclusions-rv64gc.do b/sim/coverage-exclusions-rv64gc.do index 7f073414..7fa2e407 100644 --- a/sim/coverage-exclusions-rv64gc.do +++ b/sim/coverage-exclusions-rv64gc.do @@ -27,11 +27,52 @@ # This file should be a last resort. It's preferable to put # // coverage off # statements inline with the code whenever possible. +# a hack to describe coverage exclusions without hardcoding linenumbers: +do GetLineNum.do # LZA (i<64) statement confuses coverage tool # This is ugly to exlcude the whole file - is there a better option? // coverage off isn't working coverage exclude -srcfile lzc.sv +### Exclude D$ states and logic for the I$ instance +# This is cleaner than trying to set an I$-specific pragma in cachefsm.sv (which would exclude it for the D$ instance too) +# Also exclude the write line to ready transition for the I$ since we can't get a flush during this operation. +coverage exclude -scope /dut/core/ifu/bus/icache/icache/cachefsm -fstate CurrState STATE_FLUSH STATE_FLUSH_WRITEBACK STATE_FLUSH_WRITEBACK STATE_WRITEBACK +coverage exclude -scope /dut/core/ifu/bus/icache/icache/cachefsm -ftrans CurrState STATE_WRITE_LINE->STATE_READY +# exclude unused transitions from case statement. Unfortunately the whole branch needs to be excluded I think. Expression coverage should still work. +coverage exclude -scope /dut/core/ifu/bus/icache/icache/cachefsm -linerange [GetLineNum ../src/cache/cachefsm.sv "exclusion-tag: icache state-case"] -item b 1 +# exclude branch/condition coverage: LineDirty if statement +coverage exclude -scope /dut/core/ifu/bus/icache/icache/cachefsm -linerange [GetLineNum ../src/cache/cachefsm.sv "exclusion-tag: icache FETCHStatement"] -item bc 1 +# exclude the unreachable logic +set start [GetLineNum ../src/cache/cachefsm.sv "exclusion-tag-start: icache case"] +set end [GetLineNum ../src/cache/cachefsm.sv "exclusion-tag-end: icache case"] +coverage exclude -scope /dut/core/ifu/bus/icache/icache/cachefsm -linerange $start-$end +coverage exclude -scope /dut/core/ifu/bus/icache/icache/cachefsm -linerange [GetLineNum ../src/cache/cachefsm.sv "exclusion-tag: icache WRITEBACKStatement"] +# exclude Atomic Operation logic +coverage exclude -scope /dut/core/ifu/bus/icache/icache/cachefsm -linerange [GetLineNum ../src/cache/cachefsm.sv "exclusion-tag: icache storeAMO"] -item e 1 -fecexprrow 6 +coverage exclude -scope /dut/core/ifu/bus/icache/icache/cachefsm -linerange [GetLineNum ../src/cache/cachefsm.sv "exclusion-tag: icache storeAMO1"] -item e 1 -fecexprrow 2-4 +coverage exclude -scope /dut/core/ifu/bus/icache/icache/cachefsm -linerange [GetLineNum ../src/cache/cachefsm.sv "exclusion-tag: icache AnyUpdateHit"] -item e 1 -fecexprrow 2 +# cache write logic +coverage exclude -scope /dut/core/ifu/bus/icache/icache/cachefsm -linerange [GetLineNum ../src/cache/cachefsm.sv "exclusion-tag: icache CacheW"] -item e 1 -fecexprrow 4 +# output signal logic +coverage exclude -scope /dut/core/ifu/bus/icache/icache/cachefsm -linerange [GetLineNum ../src/cache/cachefsm.sv "exclusion-tag: icache StallStates"] -item e 1 -fecexprrow 8 12 14 +set start [GetLineNum ../src/cache/cachefsm.sv "exclusion-tag-start: icache flushdirtycontrols"] +set end [GetLineNum ../src/cache/cachefsm.sv "exclusion-tag-end: icache flushdirtycontrols"] +coverage exclude -scope /dut/core/ifu/bus/icache/icache/cachefsm -linerange $start-$end +coverage exclude -scope /dut/core/ifu/bus/icache/icache/cachefsm -linerange [GetLineNum ../src/cache/cachefsm.sv "exclusion-tag: icache CacheBusW"] +coverage exclude -scope /dut/core/ifu/bus/icache/icache/cachefsm -linerange [GetLineNum ../src/cache/cachefsm.sv "exclusion-tag: icache SelAdrCauses"] -item e 1 -fecexprrow 4 10 +coverage exclude -scope /dut/core/ifu/bus/icache/icache/cachefsm -linerange [GetLineNum ../src/cache/cachefsm.sv "exclusion-tag: icache CacheBusRCauses"] -item e 1 -fecexprrow 1-2 12 +# cache.sv AdrSelMux and CacheBusAdrMux, excluding unhit Flush branch +coverage exclude -scope /dut/core/ifu/bus/icache/icache/AdrSelMux -linerange [GetLineNum ../src/generic/mux.sv "exclusion-tag: mux3"] -item b 1 +coverage exclude -scope /dut/core/ifu/bus/icache/icache/CacheBusAdrMux -linerange [GetLineNum ../src/generic/mux.sv "exclusion-tag: mux3"] -item b 1 3 +# CacheWay Dirty logic. -scope does not accept wildcards. +set numcacheways 4 +for {set i 0} {$i < $numcacheways} {incr i} { + coverage exclude -scope /dut/core/ifu/bus/icache/icache/CacheWays[$i] -linerange [GetLineNum ../src/cache/cacheway.sv "exclusion-tag: icache SetDirtyWay"] -item e 1 + coverage exclude -scope /dut/core/ifu/bus/icache/icache/CacheWays[$i] -linerange [GetLineNum ../src/cache/cacheway.sv "exclusion-tag: icache SelectedWiteWordEn"] -item e 1 -fecexprrow 4 6 + # below: flushD can't go high during an icache write b/c of pipeline stall + coverage exclude -scope /dut/core/ifu/bus/icache/icache/CacheWays[$i] -linerange [GetLineNum ../src/cache/cacheway.sv "exclusion-tag: icache SetValidEN"] -item e 1 -fecexprrow 4 +} ###################### # Toggle exclusions diff --git a/src/cache/cache.sv b/src/cache/cache.sv index ebee8f4f..c5ad8e1f 100644 --- a/src/cache/cache.sv +++ b/src/cache/cache.sv @@ -122,7 +122,7 @@ module cache #(parameter LINELEN, NUMLINES, NUMWAYS, LOGBWPL, WORDLEN, MUXINTE // Select victim way for associative caches if(NUMWAYS > 1) begin:vict cacheLRU #(NUMWAYS, SETLEN, OFFSETLEN, NUMLINES) cacheLRU( - .clk, .reset, .CacheEn, .FlushStage, .HitWay, .ValidWay, .VictimWay, .CacheSet, .LRUWriteEn, + .clk, .reset, .CacheEn, .HitWay, .ValidWay, .VictimWay, .CacheSet, .LRUWriteEn, .SetValid, .PAdr(PAdr[SETTOP-1:OFFSETLEN]), .InvalidateCache, .FlushCache); end else assign VictimWay = 1'b1; // one hot. diff --git a/src/cache/cacheLRU.sv b/src/cache/cacheLRU.sv index 87d9f072..0a1a07ca 100644 --- a/src/cache/cacheLRU.sv +++ b/src/cache/cacheLRU.sv @@ -32,8 +32,7 @@ module cacheLRU #(parameter NUMWAYS = 4, SETLEN = 9, OFFSETLEN = 5, NUMLINES = 128) ( input logic clk, - input logic reset, - input logic FlushStage, // Pipeline flush of second stage (prevent writes and bus operations) + input logic reset, input logic CacheEn, // Enable the cache memory arrays. Disable hold read data constant input logic [NUMWAYS-1:0] HitWay, // Which way is valid and matches PAdr's tag input logic [NUMWAYS-1:0] ValidWay, // Which ways for a particular set are valid, ignores tag @@ -90,16 +89,26 @@ module cacheLRU assign WayExpanded[StartIndex : EndIndex] = {{DuplicationFactor}{WayEncoded[row]}}; end - genvar r, a, s; + genvar node; assign LRUUpdate[NUMWAYS-2] = '1; - for(s = NUMWAYS-2; s >= NUMWAYS/2; s--) begin : enables - localparam p = NUMWAYS - s - 1; - localparam g = log2(p); - localparam t0 = s - p; - localparam t1 = t0 - 1; - localparam r = LOGNUMWAYS - g; - assign LRUUpdate[t0] = LRUUpdate[s] & ~WayEncoded[r]; - assign LRUUpdate[t1] = LRUUpdate[s] & WayEncoded[r]; + for(node = NUMWAYS-2; node >= NUMWAYS/2; node--) begin : enables + localparam ctr = NUMWAYS - node - 1; + localparam ctr_depth = log2(ctr); + localparam lchild = node - ctr; + localparam rchild = lchild - 1; + localparam r = LOGNUMWAYS - ctr_depth; + + // the child node will be updated if its parent was updated and + // the WayEncoded bit was the correct value. + // The if statement is only there for coverage since LRUUpdate[root] is always 1. + if (node == NUMWAYS-2) begin + assign LRUUpdate[lchild] = ~WayEncoded[r]; + assign LRUUpdate[rchild] = WayEncoded[r]; + end + else begin + assign LRUUpdate[lchild] = LRUUpdate[node] & ~WayEncoded[r]; + assign LRUUpdate[rchild] = LRUUpdate[node] & WayEncoded[r]; + end end // The root node of the LRU tree will always be selected in LRUUpdate. No mux needed. @@ -107,15 +116,15 @@ module cacheLRU mux2 #(1) LRUMuxes[NUMWAYS-3:0](CurrLRU[NUMWAYS-3:0], ~WayExpanded[NUMWAYS-3:0], LRUUpdate[NUMWAYS-3:0], NextLRU[NUMWAYS-3:0]); // Compute next victim way. - for(s = NUMWAYS-2; s >= NUMWAYS/2; s--) begin - localparam t0 = 2*s - NUMWAYS; + for(node = NUMWAYS-2; node >= NUMWAYS/2; node--) begin + localparam t0 = 2*node - NUMWAYS; localparam t1 = t0 + 1; - assign Intermediate[s] = CurrLRU[s] ? Intermediate[t0] : Intermediate[t1]; + assign Intermediate[node] = CurrLRU[node] ? Intermediate[t0] : Intermediate[t1]; end - for(s = NUMWAYS/2-1; s >= 0; s--) begin - localparam int0 = (NUMWAYS/2-1-s)*2; + for(node = NUMWAYS/2-1; node >= 0; node--) begin + localparam int0 = (NUMWAYS/2-1-node)*2; localparam int1 = int0 + 1; - assign Intermediate[s] = CurrLRU[s] ? int1[LOGNUMWAYS-1:0] : int0[LOGNUMWAYS-1:0]; + assign Intermediate[node] = CurrLRU[node] ? int1[LOGNUMWAYS-1:0] : int0[LOGNUMWAYS-1:0]; end logic [NUMWAYS-1:0] FirstZero; @@ -134,11 +143,9 @@ module cacheLRU always_ff @(posedge clk) begin if (reset) for (int set = 0; set < NUMLINES; set++) LRUMemory[set] <= '0; if(CacheEn) begin - // if((InvalidateCache | FlushCache) & ~FlushStage) for (int set = 0; set < NUMLINES; set++) LRUMemory[set] <= '0; - if (LRUWriteEn & ~FlushStage) begin + if(LRUWriteEn) LRUMemory[PAdr] <= NextLRU; - end - if(LRUWriteEn & ~FlushStage & (PAdr == CacheSet)) + if(LRUWriteEn & (PAdr == CacheSet)) CurrLRU <= #1 NextLRU; else CurrLRU <= #1 LRUMemory[CacheSet]; diff --git a/src/cache/cachefsm.sv b/src/cache/cachefsm.sv index 525d7524..90d8eaad 100644 --- a/src/cache/cachefsm.sv +++ b/src/cache/cachefsm.sv @@ -89,13 +89,13 @@ module cachefsm #(parameter READ_ONLY_CACHE = 0) ( assign AMO = CacheAtomic[1] & (&CacheRW); assign StoreAMO = AMO | CacheRW[0]; - assign AnyMiss = (StoreAMO | CacheRW[1]) & ~CacheHit & ~InvalidateCache; - assign AnyUpdateHit = (StoreAMO) & CacheHit; - assign AnyHit = AnyUpdateHit | (CacheRW[1] & CacheHit); + assign AnyMiss = (StoreAMO | CacheRW[1]) & ~CacheHit & ~InvalidateCache; // exclusion-tag: icache storeAMO + assign AnyUpdateHit = (StoreAMO) & CacheHit; // exclusion-tag: icache storeAMO1 + assign AnyHit = AnyUpdateHit | (CacheRW[1] & CacheHit); // exclusion-tag: icache AnyUpdateHit assign FlushFlag = FlushAdrFlag & FlushWayFlag; // outputs for the performance counters. - assign CacheAccess = (AMO | CacheRW[1] | CacheRW[0]) & CurrState == STATE_READY; + assign CacheAccess = (AMO | CacheRW[1] | CacheRW[0]) & CurrState == STATE_READY; // exclusion-tag: icache CacheW assign CacheMiss = CacheAccess & ~CacheHit; // special case on reset. When the fsm first exists reset the @@ -109,17 +109,18 @@ module cachefsm #(parameter READ_ONLY_CACHE = 0) ( always_comb begin NextState = STATE_READY; - case (CurrState) + case (CurrState) // exclusion-tag: icache state-case STATE_READY: if(InvalidateCache) NextState = STATE_READY; else if(FlushCache & ~READ_ONLY_CACHE) NextState = STATE_FLUSH; - else if(AnyMiss & (READ_ONLY_CACHE | ~LineDirty)) NextState = STATE_FETCH; - else if(AnyMiss & LineDirty) NextState = STATE_WRITEBACK; + else if(AnyMiss & (READ_ONLY_CACHE | ~LineDirty)) NextState = STATE_FETCH; // exclusion-tag: icache FETCHStatement + else if(AnyMiss & LineDirty) NextState = STATE_WRITEBACK; // exclusion-tag: icache WRITEBACKStatement else NextState = STATE_READY; STATE_FETCH: if(CacheBusAck) NextState = STATE_WRITE_LINE; else NextState = STATE_FETCH; STATE_WRITE_LINE: NextState = STATE_READ_HOLD; STATE_READ_HOLD: if(Stall) NextState = STATE_READ_HOLD; else NextState = STATE_READY; + // exclusion-tag-start: icache case STATE_WRITEBACK: if(CacheBusAck) NextState = STATE_FETCH; else NextState = STATE_WRITEBACK; // eviction needs a delay as the bus fsm does not correctly handle sending the write command at the same time as getting back the bus ack. @@ -129,13 +130,14 @@ module cachefsm #(parameter READ_ONLY_CACHE = 0) ( STATE_FLUSH_WRITEBACK: if(CacheBusAck & ~FlushFlag) NextState = STATE_FLUSH; else if(CacheBusAck) NextState = STATE_READ_HOLD; else NextState = STATE_FLUSH_WRITEBACK; + // exclusion-tag-end: icache case default: NextState = STATE_READY; endcase end // com back to CPU assign CacheCommitted = (CurrState != STATE_READY) & ~(READ_ONLY_CACHE & CurrState == STATE_READ_HOLD); - assign CacheStall = (CurrState == STATE_READY & (FlushCache | AnyMiss)) | + assign CacheStall = (CurrState == STATE_READY & (FlushCache | AnyMiss)) | // exclusion-tag: icache StallStates (CurrState == STATE_FETCH) | (CurrState == STATE_WRITEBACK) | (CurrState == STATE_WRITE_LINE) | // this cycle writes the sram, must keep stalling so the next cycle can read the next hit/miss unless its a write. @@ -143,12 +145,14 @@ module cachefsm #(parameter READ_ONLY_CACHE = 0) ( (CurrState == STATE_FLUSH_WRITEBACK); // write enables internal to cache assign SetValid = CurrState == STATE_WRITE_LINE; - assign SetDirty = (CurrState == STATE_READY & AnyUpdateHit) | - (CurrState == STATE_WRITE_LINE & (StoreAMO)); - assign ClearDirty = (CurrState == STATE_WRITE_LINE & ~(StoreAMO)) | - (CurrState == STATE_FLUSH & LineDirty); // This is wrong in a multicore snoop cache protocal. Dirty must be cleared concurrently and atomically with writeback. For single core cannot clear after writeback on bus ack and change flushadr. Clears the wrong set. + // coverage off -item e 1 -fecexprrow 8 assign LRUWriteEn = (CurrState == STATE_READY & AnyHit) | - (CurrState == STATE_WRITE_LINE); + (CurrState == STATE_WRITE_LINE) & ~FlushStage; + // exclusion-tag-start: icache flushdirtycontrols + assign SetDirty = (CurrState == STATE_READY & AnyUpdateHit) | // exclusion-tag: icache SetDirty + (CurrState == STATE_WRITE_LINE & (StoreAMO)); + assign ClearDirty = (CurrState == STATE_WRITE_LINE & ~(StoreAMO)) | // exclusion-tag: icache ClearDirty + (CurrState == STATE_FLUSH & LineDirty); // This is wrong in a multicore snoop cache protocal. Dirty must be cleared concurrently and atomically with writeback. For single core cannot clear after writeback on bus ack and change flushadr. Clears the wrong set. // Flush and eviction controls assign SelWriteback = (CurrState == STATE_WRITEBACK & ~CacheBusAck) | (CurrState == STATE_READY & AnyMiss & LineDirty); @@ -162,20 +166,20 @@ module cachefsm #(parameter READ_ONLY_CACHE = 0) ( (CurrState == STATE_FLUSH_WRITEBACK & CacheBusAck); assign FlushCntRst = (CurrState == STATE_FLUSH & FlushFlag & ~LineDirty) | (CurrState == STATE_FLUSH_WRITEBACK & FlushFlag & CacheBusAck); + // exclusion-tag-end: icache flushdirtycontrols // Bus interface controls - assign CacheBusRW[1] = (CurrState == STATE_READY & AnyMiss & ~LineDirty) | + assign CacheBusRW[1] = (CurrState == STATE_READY & AnyMiss & ~LineDirty) | // exclusion-tag: icache CacheBusRCauses (CurrState == STATE_FETCH & ~CacheBusAck) | (CurrState == STATE_WRITEBACK & CacheBusAck); - assign CacheBusRW[0] = (CurrState == STATE_READY & AnyMiss & LineDirty) | + assign CacheBusRW[0] = (CurrState == STATE_READY & AnyMiss & LineDirty) | // exclusion-tag: icache CacheBusW (CurrState == STATE_WRITEBACK & ~CacheBusAck) | (CurrState == STATE_FLUSH_WRITEBACK & ~CacheBusAck); - assign SelAdr = (CurrState == STATE_READY & (StoreAMO | AnyMiss)) | // changes if store delay hazard removed + assign SelAdr = (CurrState == STATE_READY & (StoreAMO | AnyMiss)) | // exclusion-tag: icache SelAdrCauses // changes if store delay hazard removed (CurrState == STATE_FETCH) | (CurrState == STATE_WRITEBACK) | (CurrState == STATE_WRITE_LINE) | resetDelay; - assign SelFetchBuffer = CurrState == STATE_WRITE_LINE | CurrState == STATE_READ_HOLD; assign CacheEn = (~Stall | FlushCache | AnyMiss) | (CurrState != STATE_READY) | reset | InvalidateCache; diff --git a/src/cache/cacheway.sv b/src/cache/cacheway.sv index e727662d..79ec65e6 100644 --- a/src/cache/cacheway.sv +++ b/src/cache/cacheway.sv @@ -97,18 +97,13 @@ module cacheway #(parameter NUMLINES=512, LINELEN = 256, TAGLEN = 26, ///////////////////////////////////////////////////////////////////////////////////////////// assign SetValidWay = SetValid & SelData; + assign SetDirtyWay = SetDirty & SelData; // exclusion-tag: icache SetDirtyWay assign ClearDirtyWay = ClearDirty & SelData; - if (!READ_ONLY_CACHE) begin - assign SetDirtyWay = SetDirty & SelData; - assign SelectedWriteWordEn = (SetValidWay | SetDirtyWay) & ~FlushStage; - end - else begin - assign SelectedWriteWordEn = SetValidWay & ~FlushStage; - end + assign SelectedWriteWordEn = (SetValidWay | SetDirtyWay) & ~FlushStage; // exclusion-tag: icache SelectedWiteWordEn + assign SetValidEN = SetValidWay & ~FlushStage; // exclusion-tag: icache SetValidEN // If writing the whole line set all write enables to 1, else only set the correct word. assign FinalByteMask = SetValidWay ? '1 : LineByteMask; // OR - assign SetValidEN = SetValidWay & ~FlushStage; ///////////////////////////////////////////////////////////////////////////////////////////// // Tag Array diff --git a/src/generic/mux.sv b/src/generic/mux.sv index 636c19c9..223d41af 100644 --- a/src/generic/mux.sv +++ b/src/generic/mux.sv @@ -40,7 +40,7 @@ module mux3 #(parameter WIDTH = 8) ( input logic [1:0] s, output logic [WIDTH-1:0] y); - assign y = s[1] ? d2 : (s[0] ? d1 : d0); + assign y = s[1] ? d2 : (s[0] ? d1 : d0); // exclusion-tag: mux3 endmodule module mux4 #(parameter WIDTH = 8) (