/////////////////////////////////////////// // dcache (data cache) fsm // // Written: ross1728@gmail.com August 25, 2021 // Implements the L1 data cache fsm // // Purpose: Controller for the dcache fsm // // A component of the CORE-V-WALLY configurable RISC-V project. // // Copyright (C) 2021-23 Harvey Mudd College & Oklahoma State University // // SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 // // Licensed under the Solderpad Hardware License v 2.1 (the “License”); you may not use this file // except in compliance with the License, or, at your option, the Apache License version 2.0. You // may obtain a copy of the License at // // https://solderpad.org/licenses/SHL-2.1/ // // Unless required by applicable law or agreed to in writing, any work distributed under the // License is distributed on an “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, // either express or implied. See the License for the specific language governing permissions // and limitations under the License. //////////////////////////////////////////////////////////////////////////////////////////////// `include "wally-config.vh" module cachefsm ( input logic clk, input logic reset, // inputs from IEU input logic FlushStage, input logic [1:0] CacheRW, input logic [1:0] CacheAtomic, input logic FlushCache, input logic InvalidateCache, // hazard inputs input logic Stall, // Bus inputs input logic CacheBusAck, // dcache internals input logic CacheHit, input logic LineDirty, input logic FlushAdrFlag, input logic FlushWayFlag, // hazard outputs output logic CacheStall, // counter outputs output logic CacheMiss, output logic CacheAccess, // Bus outputs output logic CacheCommitted, output logic [1:0] CacheBusRW, // dcache internals output logic SelAdr, output logic ClearValid, output logic ClearDirty, output logic SetDirty, output logic SetValid, output logic SelWriteback, output logic LRUWriteEn, output logic SelFlush, output logic FlushAdrCntEn, output logic FlushWayCntEn, output logic FlushCntRst, output logic SelFetchBuffer, output logic CacheEn ); logic resetDelay; logic AMO, StoreAMO; logic AnyUpdateHit, AnyHit; logic AnyMiss; logic FlushFlag; typedef enum logic [3:0]{STATE_READY, // hit states // miss states STATE_FETCH, STATE_WRITEBACK, STATE_WRITE_LINE, STATE_READ_HOLD, // required for back to back reads. structural hazard on writting SRAM // flush cache STATE_FLUSH, STATE_FLUSH_WRITEBACK} statetype; (* mark_debug = "true" *) statetype CurrState, NextState; 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 FlushFlag = FlushAdrFlag & FlushWayFlag; // outputs for the performance counters. assign CacheAccess = (AMO | CacheRW[1] | CacheRW[0]) & CurrState == STATE_READY; assign CacheMiss = CacheAccess & ~CacheHit; // special case on reset. When the fsm first exists reset the // PCNextF will no longer be pointing to the correct address. // But PCF will be the reset vector. flop #(1) resetDelayReg(.clk, .d(reset), .q(resetDelay)); always_ff @(posedge clk) if (reset | FlushStage) CurrState <= #1 STATE_READY; else CurrState <= #1 NextState; always_comb begin NextState = STATE_READY; case (CurrState) STATE_READY: if(InvalidateCache) NextState = STATE_READY; else if(FlushCache) NextState = STATE_FLUSH; // Delayed LRU update. Cannot check if victim line is dirty on this cycle. // To optimize do the fetch first, then eviction if necessary. 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; else NextState = STATE_FETCH; STATE_WRITE_LINE: NextState = STATE_READ_HOLD; STATE_READ_HOLD: if(Stall) NextState = STATE_READ_HOLD; 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. STATE_FLUSH: if(LineDirty) NextState = STATE_FLUSH_WRITEBACK; else if (FlushFlag) NextState = STATE_READ_HOLD; else NextState = STATE_FLUSH; STATE_FLUSH_WRITEBACK: if(CacheBusAck & ~FlushFlag) NextState = STATE_FLUSH; else if(CacheBusAck) NextState = STATE_READ_HOLD; else NextState = STATE_FLUSH_WRITEBACK; default: NextState = STATE_READY; endcase end // com back to CPU assign CacheCommitted = CurrState != STATE_READY; assign CacheStall = (CurrState == STATE_READY & (FlushCache | AnyMiss)) | (CurrState == STATE_FETCH) | (CurrState == STATE_WRITEBACK) | (CurrState == STATE_WRITE_LINE & ~(StoreAMO)) | // 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 SetDirty = (CurrState == STATE_READY & AnyUpdateHit) | (CurrState == STATE_WRITE_LINE & (StoreAMO)); assign ClearValid = '0; 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); assign SelFlush = (CurrState == STATE_READY & FlushCache) | (CurrState == STATE_FLUSH) | (CurrState == STATE_FLUSH_WRITEBACK); assign FlushAdrCntEn = (CurrState == STATE_FLUSH_WRITEBACK & FlushWayFlag & CacheBusAck) | (CurrState == STATE_FLUSH & FlushWayFlag & ~LineDirty); assign FlushWayCntEn = (CurrState == STATE_FLUSH & ~LineDirty) | (CurrState == STATE_FLUSH_WRITEBACK & CacheBusAck); assign FlushCntRst = (CurrState == STATE_FLUSH & FlushFlag & ~LineDirty) | (CurrState == STATE_FLUSH_WRITEBACK & FlushFlag & CacheBusAck); // Bus interface controls assign CacheBusRW[1] = (CurrState == STATE_READY & AnyMiss & ~LineDirty) | (CurrState == STATE_FETCH & ~CacheBusAck) | (CurrState == STATE_WRITEBACK & CacheBusAck); assign CacheBusRW[0] = (CurrState == STATE_READY & AnyMiss & LineDirty) | (CurrState == STATE_WRITEBACK & ~CacheBusAck) | (CurrState == STATE_FLUSH_WRITEBACK & ~CacheBusAck); // **** can this be simplified? 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 SelFetchBuffer = CurrState == STATE_WRITE_LINE | CurrState == STATE_READ_HOLD; assign CacheEn = (~Stall | FlushCache | AnyMiss) | (CurrState != STATE_READY) | reset; endmodule // cachefsm