refactor cachefsm to get full coverage

I had to exclude i$ states in coverage-exclusions-rv64gc.do,
but it's referred to by scope, which should be pretty robust
This commit is contained in:
Alec Vercruysse 2023-04-12 00:48:06 -07:00
parent 1ce2ab5daa
commit 729f81a0df
2 changed files with 128 additions and 73 deletions

View File

@ -32,6 +32,12 @@
# 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 from coverage in the I$ instance of cachefsm.
# This is cleaner than trying to set an I$-specific pragma in cachefsm.sv
# 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
coverage exclude -scope /dut/core/ifu/bus/icache/icache/cachefsm -ftrans CurrState STATE_WRITE_LINE->STATE_READY
######################
# Toggle exclusions

87
src/cache/cachefsm.sv vendored
View File

@ -86,17 +86,24 @@ module cachefsm #(parameter READ_ONLY_CACHE = 0) (
statetype CurrState, NextState;
// no atomic operations on i$
if (!READ_ONLY_CACHE) begin
assign AMO = CacheAtomic[1] & (&CacheRW);
assign StoreAMO = AMO | CacheRW[0];
assign AnyMiss = (StoreAMO | CacheRW[1]) & ~CacheHit & ~InvalidateCache;
assign AnyUpdateHit = (StoreAMO) & CacheHit;
assign AnyUpdateHit = StoreAMO & CacheHit;
assign AnyHit = AnyUpdateHit | (CacheRW[1] & CacheHit);
assign FlushFlag = FlushAdrFlag & FlushWayFlag;
assign CacheAccess = (AMO | CacheRW[1] | CacheRW[0]) & CurrState == STATE_READY; // for performance counter
end
else begin
assign AnyMiss = CacheRW[1] & ~CacheHit & ~InvalidateCache;
assign AnyUpdateHit = 0; // todo clear all RO cache of usage of this logic
assign AnyHit = CacheRW[1] & CacheHit;
assign CacheAccess = CacheRW[1] & CurrState == STATE_READY; // for performance counter
end
// outputs for the performance counters.
assign CacheAccess = (AMO | CacheRW[1] | CacheRW[0]) & CurrState == STATE_READY;
assign CacheMiss = CacheAccess & ~CacheHit;
assign CacheMiss = CacheAccess & ~CacheHit; // for performance counter
assign FlushFlag = FlushAdrFlag & FlushWayFlag;
// special case on reset. When the fsm first exists reset the
// PCNextF will no longer be pointing to the correct address.
@ -107,12 +114,14 @@ module cachefsm #(parameter READ_ONLY_CACHE = 0) (
if (reset | FlushStage) CurrState <= #1 STATE_READY;
else CurrState <= #1 NextState;
// seperating NextState logic by ro vs rw cache results in code duplication but this is needed to hit coverage.
if (!READ_ONLY_CACHE)
always_comb begin
NextState = STATE_READY;
case (CurrState)
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(FlushCache) NextState = STATE_FLUSH;
else if(AnyMiss & ~LineDirty) NextState = STATE_FETCH;
else if(AnyMiss & LineDirty) NextState = STATE_WRITEBACK;
else NextState = STATE_READY;
STATE_FETCH: if(CacheBusAck) NextState = STATE_WRITE_LINE;
@ -122,7 +131,8 @@ module cachefsm #(parameter READ_ONLY_CACHE = 0) (
else NextState = STATE_READY;
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.
// 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.
STATE_FLUSH: if(LineDirty) NextState = STATE_FLUSH_WRITEBACK;
else if (FlushFlag) NextState = STATE_READ_HOLD;
else NextState = STATE_FLUSH;
@ -131,24 +141,42 @@ module cachefsm #(parameter READ_ONLY_CACHE = 0) (
else NextState = STATE_FLUSH_WRITEBACK;
default: NextState = STATE_READY;
endcase
end
end // always_comb
else // READ_ONLY_CACHE
always_comb begin
NextState = STATE_READY;
case (CurrState)
STATE_READY: if(InvalidateCache) NextState = STATE_READY;
else if(AnyMiss) NextState = STATE_FETCH;
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;
default: NextState = STATE_READY;
endcase // case (CurrState)
end // always_comb
// com back to CPU
assign CacheCommitted = (CurrState != STATE_READY) & ~(READ_ONLY_CACHE & CurrState == STATE_READ_HOLD);
if (!READ_ONLY_CACHE) begin
assign CacheStall = (CurrState == STATE_READY & (FlushCache | AnyMiss)) |
(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.
(CurrState == STATE_FLUSH) |
(CurrState == STATE_FLUSH_WRITEBACK);
// write enables internal to cache
assign SetValid = CurrState == STATE_WRITE_LINE;
assign CacheCommitted = CurrState != STATE_READY;
assign SelAdr = (CurrState == STATE_READY & (StoreAMO | AnyMiss)) | // changes if store delay hazard removed
(CurrState == STATE_FETCH) |
(CurrState == STATE_WRITEBACK) |
(CurrState == STATE_WRITE_LINE) |
resetDelay;
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.
assign LRUWriteEn = (CurrState == STATE_READY & AnyHit) |
(CurrState == STATE_WRITE_LINE);
// Flush and eviction controls
assign SelWriteback = (CurrState == STATE_WRITEBACK & ~CacheBusAck) |
(CurrState == STATE_READY & AnyMiss & LineDirty);
@ -169,14 +197,35 @@ module cachefsm #(parameter READ_ONLY_CACHE = 0) (
assign CacheBusRW[0] = (CurrState == STATE_READY & AnyMiss & LineDirty) |
(CurrState == STATE_WRITEBACK & ~CacheBusAck) |
(CurrState == STATE_FLUSH_WRITEBACK & ~CacheBusAck);
assign SelAdr = (CurrState == STATE_READY & (StoreAMO | AnyMiss)) | // changes if store delay hazard removed
// write enable internal to cache
assign CacheEn = (~Stall | FlushCache | AnyMiss) | (CurrState != STATE_READY) | reset | InvalidateCache;
end
else begin
assign CacheStall = (CurrState == STATE_READY & (FlushCache | AnyMiss)) |
(CurrState == STATE_FETCH) |
(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.
assign CacheCommitted = (CurrState != STATE_READY) & ~(CurrState == STATE_READ_HOLD);
assign SelAdr = (CurrState == STATE_READY & AnyMiss) | // changes if store delay hazard removed
(CurrState == STATE_FETCH) |
(CurrState == STATE_WRITEBACK) |
(CurrState == STATE_WRITE_LINE) |
resetDelay;
assign SetDirty = 0;
assign ClearDirty = 0;
assign SelWriteback = 0;
assign SelFlush = 0;
assign FlushAdrCntEn = 0;
assign FlushWayCntEn = 0;
assign FlushCntRst = 0;
assign CacheBusRW[1] = (CurrState == STATE_READY & AnyMiss) |
(CurrState == STATE_FETCH & ~CacheBusAck);
assign CacheBusRW[0] = 0;
assign CacheEn = (~Stall | AnyMiss) | (CurrState != STATE_READY) | reset | InvalidateCache;
end // else: (READ_ONLY_CACHE)
// write enables internal to cache
assign SetValid = CurrState == STATE_WRITE_LINE;
assign LRUWriteEn = (CurrState == STATE_READY & AnyHit) |
(CurrState == STATE_WRITE_LINE);
assign SelFetchBuffer = CurrState == STATE_WRITE_LINE | CurrState == STATE_READ_HOLD;
assign CacheEn = (~Stall | FlushCache | AnyMiss) | (CurrState != STATE_READY) | reset | InvalidateCache;
endmodule // cachefsm