2022-01-05 05:52:42 +00:00
///////////////////////////////////////////
// dcache (data cache) fsm
//
2023-01-20 19:05:10 +00:00
// Written: Ross Thompson ross1728@gmail.com
// Created: 25 August 2021
// Modified: 20 January 2023
2022-01-05 05:52:42 +00:00
//
// Purpose: Controller for the dcache fsm
//
2023-01-20 21:01:54 +00:00
// Documentation: RISC-V System on Chip Design Chapter 7 (Figure 7.14 and Table 7.1)
2023-01-20 19:05:10 +00:00
//
2023-01-11 23:15:08 +00:00
// A component of the CORE-V-WALLY configurable RISC-V project.
2022-01-05 05:52:42 +00:00
//
2023-01-10 19:35:20 +00:00
// 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.
2022-01-07 12:58:40 +00:00
////////////////////////////////////////////////////////////////////////////////////////////////
2022-01-05 05:52:42 +00:00
`include " wally-config.vh "
2023-03-19 17:41:47 +00:00
module cachefsm # ( parameter READ_ONLY_CACHE = 0 ) (
2023-01-15 03:43:29 +00:00
input logic clk ,
input logic reset ,
2023-01-20 18:49:55 +00:00
// hazard and privilege unit
input logic Stall , // Stall the cache, preventing new accesses. In-flight access finished but does not return to READY
input logic FlushStage , // Pipeline flush of second stage (prevent writes and bus operations)
output logic CacheCommitted , // Cache has started bus operation that shouldn't be interrupted
output logic CacheStall , // Cache stalls pipeline during multicycle operation
2023-01-15 03:43:29 +00:00
// inputs from IEU
2023-01-20 18:49:55 +00:00
input logic [ 1 : 0 ] CacheRW , // [1] Read, [0] Write
input logic [ 1 : 0 ] CacheAtomic , // Atomic operation
input logic FlushCache , // Flush all dirty lines back to memory
input logic InvalidateCache , // Clear all valid bits
// Bus controls
input logic CacheBusAck , // Bus operation completed
output logic [ 1 : 0 ] CacheBusRW , // [1] Read (cache line fetch) or [0] write bus (cache line writeback)
// performance counter outputs
output logic CacheMiss , // Cache miss
2023-03-24 20:15:38 +00:00
output logic CacheAccess , // Cache access
2022-01-05 05:52:42 +00:00
2023-01-20 19:05:10 +00:00
// cache internals
input logic CacheHit , // Exactly 1 way hits
input logic LineDirty , // The selected line and way is dirty
input logic FlushAdrFlag , // On last set of a cache flush
input logic FlushWayFlag , // On the last way for any set of a cache flush
output logic SelAdr , // [0] SRAM reads from NextAdr, [1] SRAM reads from PAdr
output logic SetValid , // Set the dirty bit in the selected way and set
2023-01-20 19:09:42 +00:00
output logic ClearDirty , // Clear the dirty bit in the selected way and set
2023-01-20 19:05:10 +00:00
output logic SetDirty , // Set the dirty bit in the selected way and set
output logic SelWriteback , // Overrides cached tag check to select a specific way and set for writeback
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
output logic FlushWayCntEn , // Enable the way counter during a flush
output logic FlushCntRst , // Reset both flush counters
output logic SelFetchBuffer , // Bypass the SRAM for a load hit by directly using the read data from the ahbcacheinterface's FetchBuffer
output logic CacheEn // Enable the cache memory arrays. Disable hold read data constant
2023-01-15 03:43:29 +00:00
) ;
2022-01-05 05:52:42 +00:00
2023-03-24 20:15:38 +00:00
logic resetDelay ;
logic AMO , StoreAMO ;
logic AnyUpdateHit , AnyHit ;
logic AnyMiss ;
logic FlushFlag ;
2022-02-07 19:29:19 +00:00
2023-01-15 03:43:29 +00:00
typedef enum logic [ 3 : 0 ] { STATE_READY , // hit states
2023-03-24 20:15:38 +00:00
// 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 ;
2022-01-05 05:52:42 +00:00
2023-01-21 00:47:36 +00:00
statetype CurrState , NextState ;
2022-01-05 05:52:42 +00:00
2023-04-12 07:48:06 +00:00
// 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 AnyHit = AnyUpdateHit | ( CacheRW [ 1 ] & CacheHit ) ;
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
2022-02-07 19:29:19 +00:00
2023-04-12 07:48:06 +00:00
assign CacheMiss = CacheAccess & ~ CacheHit ; // for performance counter
2022-02-07 19:29:19 +00:00
assign FlushFlag = FlushAdrFlag & FlushWayFlag ;
2022-01-05 05:52:42 +00:00
2022-01-26 23:37:04 +00:00
// 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 ) ) ;
2022-01-05 05:52:42 +00:00
always_ff @ ( posedge clk )
2022-11-14 20:11:05 +00:00
if ( reset | FlushStage ) CurrState < = # 1 STATE_READY ;
2022-01-05 05:52:42 +00:00
else CurrState < = # 1 NextState ;
2023-04-12 07:48:06 +00:00
// 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 ) 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 ;
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 // 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
2022-01-05 05:52:42 +00:00
2022-02-08 23:52:09 +00:00
// com back to CPU
2023-04-12 07:48:06 +00:00
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 ) ;
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.
// Flush and eviction controls
assign SelWriteback = ( CurrState = = STATE_WRITEBACK & ~ CacheBusAck ) |
( CurrState = = STATE_READY & AnyMiss & LineDirty ) ;
assign SelFlush = ( CurrState = = STATE_READY & FlushCache ) |
( CurrState = = STATE_FLUSH ) |
2022-12-21 22:49:53 +00:00
( CurrState = = STATE_FLUSH_WRITEBACK ) ;
2023-04-12 07:48:06 +00:00
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 ) ;
// 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_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)
2022-02-08 23:52:09 +00:00
// write enables internal to cache
2022-12-21 22:49:53 +00:00
assign SetValid = CurrState = = STATE_WRITE_LINE ;
2023-04-12 20:32:36 +00:00
// coverage off -item e 1 -fecexprrow 8
2022-11-07 21:03:43 +00:00
assign LRUWriteEn = ( CurrState = = STATE_READY & AnyHit ) |
2023-04-12 20:32:36 +00:00
( CurrState = = STATE_WRITE_LINE ) & ~ FlushStage ;
2022-12-21 22:49:53 +00:00
assign SelFetchBuffer = CurrState = = STATE_WRITE_LINE | CurrState = = STATE_READ_HOLD ;
2022-02-07 16:43:58 +00:00
2022-01-05 05:52:42 +00:00
endmodule // cachefsm