diff --git a/src/cache/cache.sv b/src/cache/cache.sv index bf751bc31..52b54029f 100644 --- a/src/cache/cache.sv +++ b/src/cache/cache.sv @@ -90,6 +90,8 @@ module cache import cvw::*; #(parameter cvw_t P, logic [NUMWAYS-1:0] FlushWay, NextFlushWay; logic FlushWayCntEn; logic SelWriteback; + logic SelCMOWriteback; + logic SelBothWriteback; logic LRUWriteEn; logic SelFlush; logic ResetOrFlushCntRst; @@ -116,8 +118,8 @@ module cache import cvw::*; #(parameter cvw_t P, // Array of cache ways, along with victim, hit, dirty, and read merging logic cacheway #(P, PA_BITS, XLEN, NUMLINES, LINELEN, TAGLEN, OFFSETLEN, SETLEN, READ_ONLY_CACHE) CacheWays[NUMWAYS-1:0]( - .clk, .reset, .CacheEn, .CacheSet, .PAdr, .LineWriteData, .LineByteMask, - .SetValid, .ClearValid, .SetDirty, .ClearDirty, .ZeroCacheLine, .SelWriteback, .VictimWay, + .clk, .reset, .CacheEn, .CMOp, .CacheSet, .PAdr, .LineWriteData, .LineByteMask, + .SetValid, .ClearValid, .SetDirty, .ClearDirty, .ZeroCacheLine, .SelWriteback, .SelCMOWriteback, .VictimWay, .FlushWay, .SelFlush, .ReadDataLineWay, .HitWay, .ValidWay, .DirtyWay, .TagWay, .FlushStage, .InvalidateCache); // Select victim way for associative caches @@ -153,10 +155,11 @@ module cache import cvw::*; #(parameter cvw_t P, .PAdr(WordOffsetAddr), .ReadDataLine, .ReadDataWord); // Bus address for fetch, writeback, or flush writeback + assign SelBothWriteback = SelWriteback | SelCMOWriteback; mux3 #(PA_BITS) CacheBusAdrMux(.d0({PAdr[PA_BITS-1:OFFSETLEN], {OFFSETLEN{1'b0}}}), .d1({Tag, PAdr[SETTOP-1:OFFSETLEN], {OFFSETLEN{1'b0}}}), .d2({Tag, FlushAdr, {OFFSETLEN{1'b0}}}), - .s({SelFlush, SelWriteback}), .y(CacheBusAdr)); + .s({SelFlush, SelBothWriteback}), .y(CacheBusAdr)); ///////////////////////////////////////////////////////////////////////////////////////////// // Write Path @@ -222,7 +225,7 @@ module cache import cvw::*; #(parameter cvw_t P, .FlushStage, .CacheRW, .CacheAtomic, .Stall, .CacheHit, .LineDirty, .CacheStall, .CacheCommitted, .CacheMiss, .CacheAccess, .SelAdr, - .ClearDirty, .SetDirty, .SetValid, .ClearValid, .ZeroCacheLine, .SelWriteback, .SelFlush, + .ClearDirty, .SetDirty, .SetValid, .ClearValid, .ZeroCacheLine, .SelWriteback, .SelCMOWriteback, .SelFlush, .FlushAdrCntEn, .FlushWayCntEn, .FlushCntRst, .FlushAdrFlag, .FlushWayFlag, .FlushCache, .SelFetchBuffer, .InvalidateCache, .CMOp, .CacheEn, .LRUWriteEn); diff --git a/src/cache/cachefsm.sv b/src/cache/cachefsm.sv index 60b5b9fd5..6d36b78ba 100644 --- a/src/cache/cachefsm.sv +++ b/src/cache/cachefsm.sv @@ -61,6 +61,7 @@ module cachefsm import cvw::*; #(parameter cvw_t P, output logic ClearDirty, // Clear the dirty bit in the selected way and set output logic ZeroCacheLine, // Write zeros to all bytes of cacheline output logic SelWriteback, // Overrides cached tag check to select a specific way and set for writeback + output logic SelCMOWriteback, // Overrides cached tag check to select a specific way and set for writeback for both data and tag output logic LRUWriteEn, // Update the LRU state output logic SelFlush, // [0] Use SelAdr, [1] SRAM reads/writes from FlushAdr output logic FlushAdrCntEn, // Enable the counter for Flush Adr @@ -83,7 +84,11 @@ module cachefsm import cvw::*; #(parameter cvw_t P, STATE_READ_HOLD, // required for back to back reads. structural hazard on writting SRAM // flush cache STATE_FLUSH, - STATE_FLUSH_WRITEBACK} statetype; + STATE_FLUSH_WRITEBACK, + // CMO states + STATE_CMO_WRITEBACK, + STATE_CMO_DONE + } statetype; statetype CurrState, NextState; @@ -112,17 +117,17 @@ module cachefsm import cvw::*; #(parameter cvw_t P, STATE_READY: if(InvalidateCache) NextState = STATE_READY; // exclusion-tag: dcache InvalidateCheck else if(FlushCache & ~READ_ONLY_CACHE) NextState = STATE_FLUSH; else if(AnyMiss & (READ_ONLY_CACHE | ~LineDirty)) NextState = STATE_FETCH; // exclusion-tag: icache FETCHStatement - else if(AnyMiss | CMOp[1] | CMOp[2]) /* & LineDirty */NextState = STATE_WRITEBACK; // exclusion-tag: icache WRITEBACKStatement + else if(AnyMiss) /* & LineDirty */ NextState = STATE_WRITEBACK; // exclusion-tag: icache WRITEBACKStatement + else if((CMOp[1] | CMOp[2]) & CacheHit) NextState = STATE_CMO_WRITEBACK; else NextState = STATE_READY; - STATE_FETCH: if(CacheBusAck & ~(CMOp[1] | CMOp[2])) NextState = STATE_WRITE_LINE; - else if(CacheBusAck) /* CMOp[1] | CMOp[2] */ NextState = STATE_READY; + STATE_FETCH: if(CacheBusAck) NextState = STATE_WRITE_LINE; + else if(CacheBusAck) NextState = STATE_READY; 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 & (CMOp[1] | CMOp[2])) NextState = STATE_READ_HOLD; - else if(CacheBusAck) NextState = STATE_FETCH; + 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. STATE_FLUSH: if(LineDirty) NextState = STATE_FLUSH_WRITEBACK; @@ -131,36 +136,42 @@ module cachefsm import cvw::*; #(parameter cvw_t P, STATE_FLUSH_WRITEBACK: if(CacheBusAck & ~FlushFlag) NextState = STATE_FLUSH; else if(CacheBusAck) NextState = STATE_READ_HOLD; else NextState = STATE_FLUSH_WRITEBACK; + + STATE_CMO_WRITEBACK: if(CacheBusAck & (CMOp[1] | CMOp[2])) NextState = STATE_CMO_DONE; + else NextState = STATE_CMO_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 CacheCommitted = (CurrState != STATE_READY) & ~(READ_ONLY_CACHE & (CurrState == STATE_READ_HOLD | CurrState == STATE_CMO_DONE)); assign CacheStall = (CurrState == STATE_READY & (FlushCache | AnyMiss | CMOp[1] | CMOp[2])) | // 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. (CurrState == STATE_FLUSH) | - (CurrState == STATE_FLUSH_WRITEBACK); + (CurrState == STATE_FLUSH_WRITEBACK) | + (CurrState == STATE_CMO_WRITEBACK); // write enables internal to cache - assign SetValid = CurrState == STATE_WRITE_LINE | (CurrState == STATE_READY & CMOp[3]); + assign SetValid = CurrState == STATE_WRITE_LINE | + (CurrState == STATE_READY & CMOp[3]); // *** RT: NOT completely right has to be a hit assign ClearValid = P.ZICBOM_SUPPORTED & ((CurrState == STATE_READY & CMOp[0]) | - (CurrState == STATE_WRITEBACK & CMOp[1])); + (CurrState == STATE_CMO_DONE & CMOp[2])); // coverage off -item e 1 -fecexprrow 8 assign LRUWriteEn = (CurrState == STATE_READY & AnyHit) | (CurrState == STATE_WRITE_LINE) & ~FlushStage; // exclusion-tag-start: icache flushdirtycontrols - assign SetDirty = (CurrState == STATE_READY & (AnyUpdateHit | CMOp[3])) | // exclusion-tag: icache SetDirty + assign SetDirty = (CurrState == STATE_READY & (AnyUpdateHit | CMOp[3])) | // exclusion-tag: icache SetDirty *** NOT completely right has to be a hit for CMOp[3] (CurrState == STATE_WRITE_LINE & (CacheRW[0])); assign ClearDirty = (CurrState == STATE_WRITE_LINE & ~(CacheRW[0])) | // 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 - (P.ZICBOM_SUPPORTED & CurrState == STATE_WRITEBACK & (CMOp[1] | CMOp[2] | CMOp[3])); - assign ZeroCacheLine = CurrState == STATE_READY & CMOp[3]; + (P.ZICBOM_SUPPORTED & CurrState == STATE_CMO_DONE & (CMOp[1] | CMOp[2])); + assign ZeroCacheLine = CurrState == STATE_READY & CMOp[3]; // *** RT: NOT completely right assign SelWriteback = (CurrState == STATE_WRITEBACK & ~CacheBusAck) | (CurrState == STATE_READY & AnyMiss & LineDirty); + assign SelCMOWriteback = CurrState == STATE_CMO_WRITEBACK; assign SelFlush = (CurrState == STATE_READY & FlushCache) | (CurrState == STATE_FLUSH) | @@ -179,13 +190,15 @@ module cachefsm import cvw::*; #(parameter cvw_t P, (CurrState == STATE_FETCH & ~CacheBusAck) | (CurrState == STATE_WRITEBACK & CacheBusAck); assign CacheBusRW[0] = (CurrState == STATE_READY & AnyMiss & LineDirty) | // exclusion-tag: icache CacheBusW - (CurrState == STATE_WRITEBACK & ~CacheBusAck) | - (CurrState == STATE_FLUSH_WRITEBACK & ~CacheBusAck); + (CurrState == STATE_WRITEBACK & ~CacheBusAck) | + (CurrState == STATE_FLUSH_WRITEBACK & ~CacheBusAck) | + (P.ZICBOM_SUPPORTED & CurrState == STATE_CMO_WRITEBACK & (CMOp[1] | CMOp[2]) & ~CacheBusAck); assign SelAdr = (CurrState == STATE_READY & (CacheRW[0] | AnyMiss | (|CMOp))) | // exclusion-tag: icache SelAdrCauses // changes if store delay hazard removed (CurrState == STATE_FETCH) | (CurrState == STATE_WRITEBACK) | (CurrState == STATE_WRITE_LINE) | + (CurrState == STATE_CMO_WRITEBACK) | resetDelay; assign SelFetchBuffer = CurrState == STATE_WRITE_LINE | CurrState == STATE_READ_HOLD; assign CacheEn = (~Stall | FlushCache | AnyMiss) | (CurrState != STATE_READY) | reset | InvalidateCache; // exclusion-tag: dcache CacheEn diff --git a/src/cache/cacheway.sv b/src/cache/cacheway.sv index fb361977a..85d2b36ab 100644 --- a/src/cache/cacheway.sv +++ b/src/cache/cacheway.sv @@ -33,6 +33,7 @@ module cacheway import cvw::*; #(parameter cvw_t P, input logic clk, input logic reset, input logic FlushStage, // Pipeline flush of second stage (prevent writes and bus operations) + input logic [3:0] CMOp, // 1: cbo.inval; 2: cbo.flush; 4: cbo.clean; 8: cbo.zero input logic CacheEn, // Enable the cache memory arrays. Disable hold read data constant input logic [$clog2(NUMLINES)-1:0] CacheSet, // Cache address, the output of the address select mux, NextAdr, PAdr, or FlushAdr input logic [PA_BITS-1:0] PAdr, // Physical address @@ -43,6 +44,7 @@ module cacheway import cvw::*; #(parameter cvw_t P, input logic ZeroCacheLine, // Write zeros to all bytes of a cache line input logic ClearDirty, // Clear the dirty bit in the selected way and set input logic SelWriteback, // Overrides cached tag check to select a specific way and set for writeback + input logic SelCMOWriteback, // Overrides cached tag check to select a specific way and set for writeback for both data and tag input logic SelFlush, // [0] Use SelAdr, [1] SRAM reads/writes from FlushAdr input logic VictimWay, // LRU selected this way as victim to evict input logic FlushWay, // This way is selected for flush and possible writeback if dirty @@ -78,7 +80,7 @@ module cacheway import cvw::*; #(parameter cvw_t P, logic SelData; logic SelNotHit2; - if (P.ZICBOM_SUPPORTED) begin : cbologic + if (P.ZICBOZ_SUPPORTED) begin : cbologic assign SelNotHit2 = SetValid & ~(ZeroCacheLine & HitWay); end else begin : cbologic assign SelNotHit2 = SetValid; @@ -93,7 +95,9 @@ module cacheway import cvw::*; #(parameter cvw_t P, // coverage off -item e 1 -fecexprrow 3 // nonzero ways will never see SelFlush=0 while FlushWay=1 since FlushWay only advances on a subset of SelFlush assertion cases. assign FlushWayEn = FlushWay & SelFlush; + // *** RT: This is slopy. I should refactor to have the fsm issue two types of writeback commands assign SelNonHit = FlushWayEn | SelNotHit2 | SelWriteback; + //assign SelNonHit = FlushWayEn | SelNotHit2 | SelWriteback; end else begin:flushlogic // no flush operation for read-only caches. assign SelTag = VictimWay; assign SelNonHit = SelNotHit2; @@ -124,7 +128,7 @@ module cacheway import cvw::*; #(parameter cvw_t P, .din(PAdr[PA_BITS-1:OFFSETLEN+INDEXLEN]), .we(SetValidEN)); // AND portion of distributed tag multiplexer - assign TagWay = SelTag ? ReadTag : '0; // AND part of AOMux + assign TagWay = SelData ? ReadTag : '0; // AND part of AOMux assign DirtyWay = SelTag & Dirty & ValidWay; assign HitWay = ValidWay & (ReadTag == PAdr[PA_BITS-1:OFFSETLEN+INDEXLEN]);