2022-01-05 05:40:37 +00:00
///////////////////////////////////////////
// cache (data cache)
//
// Written: ross1728@gmail.com July 07, 2021
// Implements the L1 data cache
//
// Purpose: Storage for data and meta data.
//
// A component of the Wally configurable RISC-V project.
//
// Copyright (C) 2021 Harvey Mudd College & Oklahoma State University
//
2022-01-07 12:58:40 +00:00
// MIT LICENSE
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
2022-01-05 05:40:37 +00:00
//
2022-01-07 12:58:40 +00:00
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
2022-01-05 05:40:37 +00:00
//
2022-01-07 12:58:40 +00:00
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
// BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
// OR OTHER DEALINGS IN THE SOFTWARE.
////////////////////////////////////////////////////////////////////////////////////////////////
2022-01-05 05:40:37 +00:00
`include " wally-config.vh "
2022-08-02 02:06:36 +00:00
module cache # ( parameter LINELEN , NUMLINES , NUMWAYS , LOGBWPL , WORDLEN , MUXINTERVAL , DCACHE ) (
2022-08-17 21:09:20 +00:00
input logic clk ,
input logic reset ,
2022-01-05 05:40:37 +00:00
// cpu side
2022-11-07 21:03:43 +00:00
input logic Flush ,
2022-08-17 21:09:20 +00:00
input logic CPUBusy ,
2022-11-01 20:23:24 +00:00
input logic [ 1 : 0 ] CacheRW ,
input logic [ 1 : 0 ] CacheAtomic ,
2022-08-17 21:09:20 +00:00
input logic FlushCache ,
input logic InvalidateCache ,
input logic [ 11 : 0 ] NextAdr , // virtual address, but we only use the lower 12 bits.
input logic [ `PA_BITS - 1 : 0 ] PAdr , // physical address
2022-08-02 02:06:36 +00:00
input logic [ ( WORDLEN - 1 ) / 8 : 0 ] ByteMask ,
2022-11-14 03:36:12 +00:00
input logic [ WORDLEN - 1 : 0 ] CacheWriteData ,
2022-08-17 21:09:20 +00:00
output logic CacheCommitted ,
output logic CacheStall ,
2022-01-06 04:37:53 +00:00
// to performance counters to cpu
2022-08-17 21:09:20 +00:00
output logic CacheMiss ,
output logic CacheAccess ,
2022-01-06 04:37:53 +00:00
// lsu control
2022-10-19 20:08:23 +00:00
input logic SelHPTW ,
2022-01-06 04:37:53 +00:00
// Bus fsm interface
2022-09-23 16:46:53 +00:00
output logic [ 1 : 0 ] CacheBusRW ,
2022-08-17 21:09:20 +00:00
input logic CacheBusAck ,
2022-11-09 23:52:50 +00:00
input logic SelBusBeat ,
input logic [ LOGBWPL - 1 : 0 ] BeatCount ,
2022-08-25 17:44:39 +00:00
input logic [ LINELEN - 1 : 0 ] FetchBuffer ,
2022-08-17 21:09:20 +00:00
output logic [ `PA_BITS - 1 : 0 ] CacheBusAdr ,
output logic [ WORDLEN - 1 : 0 ] ReadDataWord ) ;
2022-01-05 05:40:37 +00:00
2022-02-03 15:36:11 +00:00
// Cache parameters
2022-02-10 01:29:15 +00:00
localparam LINEBYTELEN = LINELEN / 8 ;
localparam OFFSETLEN = $clog2 ( LINEBYTELEN ) ;
localparam SETLEN = $clog2 ( NUMLINES ) ;
localparam SETTOP = SETLEN + OFFSETLEN ;
localparam TAGLEN = `PA_BITS - SETTOP ;
2022-07-08 23:56:57 +00:00
localparam WORDSPERLINE = LINELEN / WORDLEN ;
2022-02-10 01:29:15 +00:00
localparam FlushAdrThreshold = NUMLINES - 1 ;
2022-01-05 05:40:37 +00:00
2022-02-12 04:41:36 +00:00
logic SelAdr ;
2022-02-10 01:29:15 +00:00
logic [ SETLEN - 1 : 0 ] RAdr ;
2022-11-14 03:36:12 +00:00
logic [ LINELEN - 1 : 0 ] LineWriteData ;
2022-02-12 04:27:27 +00:00
logic ClearValid ;
logic ClearDirty ;
2022-02-10 01:29:15 +00:00
logic [ LINELEN - 1 : 0 ] ReadDataLineWay [ NUMWAYS - 1 : 0 ] ;
2022-07-23 04:29:14 +00:00
logic [ NUMWAYS - 1 : 0 ] HitWay ;
2022-02-10 01:29:15 +00:00
logic CacheHit ;
2022-02-13 21:06:18 +00:00
logic SetDirty ;
logic SetValid ;
2022-02-10 01:29:15 +00:00
logic [ NUMWAYS - 1 : 0 ] VictimWay ;
logic [ NUMWAYS - 1 : 0 ] VictimDirtyWay ;
logic VictimDirty ;
logic [ TAGLEN - 1 : 0 ] VictimTagWay [ NUMWAYS - 1 : 0 ] ;
logic [ TAGLEN - 1 : 0 ] VictimTag ;
logic [ SETLEN - 1 : 0 ] FlushAdr ;
logic [ SETLEN - 1 : 0 ] FlushAdrP1 ;
logic FlushAdrCntEn ;
logic FlushAdrCntRst ;
logic FlushAdrFlag ;
logic FlushWayFlag ;
logic [ NUMWAYS - 1 : 0 ] FlushWay ;
logic [ NUMWAYS - 1 : 0 ] NextFlushWay ;
logic FlushWayCntEn ;
logic FlushWayCntRst ;
logic SelEvict ;
logic LRUWriteEn ;
logic SelFlush ;
logic ResetOrFlushAdr , ResetOrFlushWay ;
logic [ NUMWAYS - 1 : 0 ] SelectedWay ;
logic [ NUMWAYS - 1 : 0 ] SetValidWay , ClearValidWay , SetDirtyWay , ClearDirtyWay ;
2022-07-19 04:37:18 +00:00
logic [ LINELEN - 1 : 0 ] ReadDataLine , ReadDataLineCache ;
2022-03-11 18:44:04 +00:00
logic [ $clog2 ( LINELEN / 8 ) - $clog2 ( MUXINTERVAL / 8 ) - 1 : 0 ] WordOffsetAddr ;
2022-07-19 04:37:18 +00:00
logic SelBusBuffer ;
2022-07-23 03:42:39 +00:00
logic SRAMEnable ;
2022-07-19 04:37:18 +00:00
2022-08-02 02:06:36 +00:00
localparam LOGLLENBYTES = $clog2 ( WORDLEN / 8 ) ;
localparam CACHEWORDSPERLINE = `DCACHE_LINELENINBITS / WORDLEN ;
localparam LOGCWPL = $clog2 ( CACHEWORDSPERLINE ) ;
logic [ CACHEWORDSPERLINE - 1 : 0 ] MemPAdrDecoded ;
2022-07-19 04:37:18 +00:00
logic [ LINELEN / 8 - 1 : 0 ] LineByteMask , DemuxedByteMask , LineByteMux ;
genvar index ;
2022-02-04 19:31:32 +00:00
2022-02-03 15:36:11 +00:00
/////////////////////////////////////////////////////////////////////////////////////////////
// Read Path
/////////////////////////////////////////////////////////////////////////////////////////////
// Choose read address (RAdr). Normally use NextAdr, but use PAdr during stalls
// and FlushAdr when handling D$ flushes
mux3 # ( SETLEN ) AdrSelMux (
. d0 ( NextAdr [ SETTOP - 1 : OFFSETLEN ] ) , . d1 ( PAdr [ SETTOP - 1 : OFFSETLEN ] ) , . d2 ( FlushAdr ) ,
2022-10-19 20:08:23 +00:00
. s ( { SelFlush , ( SelAdr | SelHPTW ) } ) , . y ( RAdr ) ) ;
2022-02-03 15:36:11 +00:00
// Array of cache ways, along with victim, hit, dirty, and read merging logic
2022-05-03 10:53:20 +00:00
cacheway # ( NUMLINES , LINELEN , TAGLEN , OFFSETLEN , SETLEN )
2022-11-14 03:36:12 +00:00
CacheWays [ NUMWAYS - 1 : 0 ] ( . clk , . reset , . ce ( SRAMEnable ) , . RAdr , . PAdr , . LineWriteData , . LineByteMask ,
2022-02-10 17:40:10 +00:00
. SetValidWay , . ClearValidWay , . SetDirtyWay , . ClearDirtyWay , . SelEvict , . VictimWay ,
2022-11-07 21:03:43 +00:00
. FlushWay , . SelFlush , . ReadDataLineWay , . HitWay , . VictimDirtyWay , . VictimTagWay , . Flush ,
2022-07-23 04:36:27 +00:00
. Invalidate ( InvalidateCache ) ) ;
2022-01-05 16:01:03 +00:00
if ( NUMWAYS > 1 ) begin : vict
2022-02-03 15:36:11 +00:00
cachereplacementpolicy # ( NUMWAYS , SETLEN , OFFSETLEN , NUMLINES ) cachereplacementpolicy (
2022-11-07 21:03:43 +00:00
. clk , . reset , . ce ( SRAMEnable ) , . HitWay , . VictimWay , . RAdr , . LRUWriteEn ( LRUWriteEn & ~ Flush ) ) ;
2022-02-03 15:36:11 +00:00
end else assign VictimWay = 1 'b1 ; // one hot.
2022-02-13 21:47:27 +00:00
assign CacheHit = | HitWay ;
2022-01-05 05:40:37 +00:00
assign VictimDirty = | VictimDirtyWay ;
2022-02-03 16:52:22 +00:00
// ReadDataLineWay is a 2d array of cache line len by number of ways.
2022-01-05 05:40:37 +00:00
// Need to OR together each way in a bitwise manner.
// Final part of the AO Mux. First is the AND in the cacheway.
2022-07-19 04:37:18 +00:00
or_rows # ( NUMWAYS , LINELEN ) ReadDataAOMux ( . a ( ReadDataLineWay ) , . y ( ReadDataLineCache ) ) ;
2022-02-04 20:18:10 +00:00
or_rows # ( NUMWAYS , TAGLEN ) VictimTagAOMux ( . a ( VictimTagWay ) , . y ( VictimTag ) ) ;
2022-01-05 05:40:37 +00:00
2022-03-11 18:44:04 +00:00
// like to fix this.
if ( DCACHE )
2022-08-02 02:06:36 +00:00
mux2 # ( LOGBWPL ) WordAdrrMux ( . d0 ( PAdr [ $clog2 ( LINELEN / 8 ) - 1 : $clog2 ( MUXINTERVAL / 8 ) ] ) ,
2022-11-09 23:52:50 +00:00
. d1 ( BeatCount ) , . s ( SelBusBeat ) ,
2022-03-11 20:58:21 +00:00
. y ( WordOffsetAddr ) ) ;
2022-03-11 18:44:04 +00:00
else assign WordOffsetAddr = PAdr [ $clog2 ( LINELEN / 8 ) - 1 : $clog2 ( MUXINTERVAL / 8 ) ] ;
2022-08-25 17:44:39 +00:00
mux2 # ( LINELEN ) EarlyReturnMux ( ReadDataLineCache , FetchBuffer , SelBusBuffer , ReadDataLine ) ;
2022-07-19 04:37:18 +00:00
2022-08-02 02:06:36 +00:00
subcachelineread # ( LINELEN , WORDLEN , MUXINTERVAL ) subcachelineread (
2022-07-23 04:29:14 +00:00
. PAdr ( WordOffsetAddr ) ,
2022-03-11 18:44:04 +00:00
. ReadDataLine , . ReadDataWord ) ;
2022-03-11 17:03:36 +00:00
2022-02-03 15:36:11 +00:00
/////////////////////////////////////////////////////////////////////////////////////////////
2022-02-08 23:52:09 +00:00
// Write Path: Write data and address. Muxes between writes from bus and writes from CPU.
2022-02-03 15:36:11 +00:00
/////////////////////////////////////////////////////////////////////////////////////////////
2022-11-14 03:36:12 +00:00
logic [ LINELEN - 1 : 0 ] CacheWriteDataDup ;
assign CacheWriteDataDup = { WORDSPERLINE { CacheWriteData } } ;
2022-07-19 04:37:18 +00:00
2022-08-02 02:06:36 +00:00
onehotdecoder # ( LOGCWPL ) adrdec (
. bin ( PAdr [ LOGCWPL + LOGLLENBYTES - 1 : LOGLLENBYTES ] ) , . decoded ( MemPAdrDecoded ) ) ;
for ( index = 0 ; index < 2 * * LOGCWPL ; index + + ) begin
assign DemuxedByteMask [ ( index + 1 ) * ( WORDLEN / 8 ) - 1 : index * ( WORDLEN / 8 ) ] = MemPAdrDecoded [ index ] ? ByteMask : '0 ;
2022-07-19 04:37:18 +00:00
end
2022-08-02 03:09:11 +00:00
2022-07-19 04:37:18 +00:00
assign LineByteMux = SetValid & ~ SetDirty ? '1 : ~ DemuxedByteMask ; // If load miss set all muxes to 1.
assign LineByteMask = ~ SetValid & ~ SetDirty ? '0 : ~ SetValid & SetDirty ? DemuxedByteMask : '1 ; // if store hit only enable the word and subword bytes, else write all bytes.
for ( index = 0 ; index < LINELEN / 8 ; index + + ) begin
2022-11-14 03:36:12 +00:00
mux2 # ( 8 ) WriteDataMux ( . d0 ( CacheWriteDataDup [ 8 * index + 7 : 8 * index ] ) ,
. d1 ( FetchBuffer [ 8 * index + 7 : 8 * index ] ) , . s ( LineByteMux [ index ] ) , . y ( LineWriteData [ 8 * index + 7 : 8 * index ] ) ) ;
2022-07-19 04:37:18 +00:00
end
2022-08-25 17:44:39 +00:00
2022-07-05 22:36:54 +00:00
mux3 # ( `PA_BITS ) CacheBusAdrMux ( . d0 ( { PAdr [ `PA_BITS - 1 : OFFSETLEN ] , { OFFSETLEN { 1 'b0 } } } ) ,
. d1 ( { VictimTag , PAdr [ SETTOP - 1 : OFFSETLEN ] , { OFFSETLEN { 1 'b0 } } } ) ,
. d2 ( { VictimTag , FlushAdr , { OFFSETLEN { 1 'b0 } } } ) ,
2022-02-12 05:10:58 +00:00
. s ( { SelFlush , SelEvict } ) , . y ( CacheBusAdr ) ) ;
2022-02-03 15:36:11 +00:00
/////////////////////////////////////////////////////////////////////////////////////////////
// Flush address and way generation during flush
/////////////////////////////////////////////////////////////////////////////////////////////
assign ResetOrFlushAdr = reset | FlushAdrCntRst ;
2022-02-12 05:10:58 +00:00
flopenr # ( SETLEN ) FlushAdrReg ( . clk , . reset ( ResetOrFlushAdr ) , . en ( FlushAdrCntEn ) ,
. d ( FlushAdrP1 ) , . q ( FlushAdr ) ) ;
2022-01-05 05:40:37 +00:00
assign FlushAdrP1 = FlushAdr + 1 'b1 ;
2022-02-03 15:36:11 +00:00
assign FlushAdrFlag = ( FlushAdr = = FlushAdrThreshold [ SETLEN - 1 : 0 ] ) ;
assign ResetOrFlushWay = reset | FlushWayCntRst ;
2022-02-12 05:10:58 +00:00
flopenl # ( NUMWAYS ) FlushWayReg ( . clk , . load ( ResetOrFlushWay ) , . en ( FlushWayCntEn ) ,
. val ( { { NUMWAYS - 1 { 1 'b0 } } , 1 'b1 } ) , . d ( NextFlushWay ) , . q ( FlushWay ) ) ;
2022-02-03 15:36:11 +00:00
assign FlushWayFlag = FlushWay [ NUMWAYS - 1 ] ;
2022-07-06 23:34:30 +00:00
if ( NUMWAYS > 1 ) assign NextFlushWay = { FlushWay [ NUMWAYS - 2 : 0 ] , FlushWay [ NUMWAYS - 1 ] } ;
else assign NextFlushWay = FlushWay [ NUMWAYS - 1 ] ;
2022-01-05 05:40:37 +00:00
2022-02-08 23:52:09 +00:00
/////////////////////////////////////////////////////////////////////////////////////////////
// Write Path: Write Enables
/////////////////////////////////////////////////////////////////////////////////////////////
2022-07-23 04:29:14 +00:00
mux3 # ( NUMWAYS ) selectwaymux ( HitWay , VictimWay , FlushWay ,
2022-02-13 21:06:18 +00:00
{ SelFlush , SetValid } , SelectedWay ) ;
assign SetValidWay = SetValid ? SelectedWay : '0 ;
2022-02-07 23:23:09 +00:00
assign ClearValidWay = ClearValid ? SelectedWay : '0 ;
2022-02-13 21:06:18 +00:00
assign SetDirtyWay = SetDirty ? SelectedWay : '0 ;
2022-02-08 23:52:09 +00:00
assign ClearDirtyWay = ClearDirty ? SelectedWay : '0 ;
2022-02-07 23:23:09 +00:00
2022-02-03 15:36:11 +00:00
/////////////////////////////////////////////////////////////////////////////////////////////
// Cache FSM
/////////////////////////////////////////////////////////////////////////////////////////////
2022-09-23 16:46:53 +00:00
cachefsm cachefsm ( . clk , . reset , . CacheBusRW , . CacheBusAck ,
2022-11-07 21:03:43 +00:00
. Flush , . CacheRW , . CacheAtomic , . CPUBusy ,
2022-02-03 15:36:11 +00:00
. CacheHit , . VictimDirty , . CacheStall , . CacheCommitted ,
2022-02-12 04:23:47 +00:00
. CacheMiss , . CacheAccess , . SelAdr ,
2022-02-13 21:06:18 +00:00
. ClearValid , . ClearDirty , . SetDirty ,
. SetValid , . SelEvict , . SelFlush ,
2022-02-03 15:36:11 +00:00
. FlushAdrCntEn , . FlushWayCntEn , . FlushAdrCntRst ,
2022-07-19 04:37:18 +00:00
. FlushWayCntRst , . FlushAdrFlag , . FlushWayFlag , . FlushCache , . SelBusBuffer ,
2022-07-23 04:36:27 +00:00
. InvalidateCache ,
2022-07-23 04:29:14 +00:00
. SRAMEnable ,
2022-02-08 03:59:18 +00:00
. LRUWriteEn ) ;
2022-02-03 15:36:11 +00:00
endmodule