cvw/pipelined/src/cache/cache.sv

208 lines
11 KiB
Systemverilog
Raw Normal View History

///////////////////////////////////////////
2023-01-07 23:39:13 +00:00
// cache
//
// Written: ross1728@gmail.com July 07, 2021
2023-01-07 23:39:13 +00:00
// Implements the L1 instruction/data cache
//
// Purpose: Storage for data and meta data.
//
2023-01-20 18:41:57 +00:00
// Documentation: RISC-V System on Chip Design Chapter 7 (Figures 7.9, 7.11, and 7.20)
//
2023-01-11 23:15:08 +00:00
// A component of the CORE-V-WALLY configurable RISC-V project.
//
2023-01-07 23:39:13 +00:00
// Copyright (C) 2021-23 Harvey Mudd College & Oklahoma State University
//
2023-01-07 23:39:13 +00:00
// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1
//
2023-01-07 23:39:13 +00:00
// 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
//
2023-01-07 23:39:13 +00:00
// 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 cache #(parameter LINELEN, NUMLINES, NUMWAYS, LOGBWPL, WORDLEN, MUXINTERVAL, DCACHE) (
2023-01-07 23:39:13 +00:00
input logic clk,
input logic reset,
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)
// cpu side
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
input logic [11:0] NextAdr, // Virtual address, but we only use the lower 12 bits.
input logic [`PA_BITS-1:0] PAdr, // Physical address
input logic [(WORDLEN-1)/8:0] ByteMask, // Which bytes to write (D$ only)
input logic [WORDLEN-1:0] CacheWriteData, // Data to write to cache (D$ only)
output logic CacheCommitted, // Cache has started bus operation that shouldn't be interrupted
output logic CacheStall, // Cache stalls pipeline during multicycle operation
output logic [WORDLEN-1:0] ReadDataWord, // Word read from cache (goes to CPU and bus)
// to performance counters to cpu
output logic CacheMiss, // Cache miss
output logic CacheAccess, // Cache access
// lsu control
input logic SelHPTW, // Use PAdr from Hardware Page Table Walker rather than NextAdr
// Bus fsm interface
input logic CacheBusAck, // Bus operation completed
input logic SelBusBeat, // Word in cache line comes from BeatCount
input logic [LOGBWPL-1:0] BeatCount, // Beat in burst
input logic [LINELEN-1:0] FetchBuffer, // Buffer long enough to hold entire cache line arriving from bus
2023-01-20 18:49:55 +00:00
output logic [1:0] CacheBusRW, // [1] Read (cache line fetch) or [0] write bus (cache line writeback)
2023-01-07 23:39:13 +00:00
output logic [`PA_BITS-1:0] CacheBusAdr // Address for bus access
);
2022-02-03 15:36:11 +00:00
// Cache parameters
2023-01-07 23:39:13 +00:00
localparam LINEBYTELEN = LINELEN/8; // Line length in bytes
localparam OFFSETLEN = $clog2(LINEBYTELEN); // Number of bits in offset field
localparam SETLEN = $clog2(NUMLINES); // Number of set bits
localparam SETTOP = SETLEN+OFFSETLEN; // Number of set plus offset bits
localparam TAGLEN = `PA_BITS - SETTOP; // Number of tag bits
2023-01-20 18:41:57 +00:00
localparam CACHEWORDSPERLINE = LINELEN/WORDLEN;// Number of words in cache line
localparam LOGCWPL = $clog2(CACHEWORDSPERLINE);// Log2 of ^
2023-01-07 23:39:13 +00:00
localparam FLUSHADRTHRESHOLD = NUMLINES - 1; // Used to determine when flush is complete
localparam LOGLLENBYTES = $clog2(WORDLEN/8); // Number of bits to address a word
2023-01-20 18:41:57 +00:00
2022-12-23 07:58:14 +00:00
2023-01-07 23:39:13 +00:00
logic SelAdr;
logic [1:0] AdrSelMuxSel;
logic [SETLEN-1:0] CAdr;
logic [LINELEN-1:0] LineWriteData;
logic ClearValid, ClearDirty, SetDirty, SetValid;
logic [LINELEN-1:0] ReadDataLineWay [NUMWAYS-1:0];
logic [NUMWAYS-1:0] HitWay, ValidWay;
logic CacheHit;
logic [NUMWAYS-1:0] VictimWay, DirtyWay;
logic LineDirty;
logic [TAGLEN-1:0] TagWay [NUMWAYS-1:0];
logic [TAGLEN-1:0] Tag;
logic [SETLEN-1:0] FlushAdr, NextFlushAdr, FlushAdrP1;
logic FlushAdrCntEn, FlushCntRst;
logic FlushAdrFlag, FlushWayFlag;
logic [NUMWAYS-1:0] FlushWay, NextFlushWay;
logic FlushWayCntEn;
logic SelWriteback;
logic LRUWriteEn;
logic SelFlush;
logic ResetOrFlushCntRst;
logic [LINELEN-1:0] ReadDataLine, ReadDataLineCache;
logic SelFetchBuffer;
logic CacheEn;
logic [CACHEWORDSPERLINE-1:0] MemPAdrDecoded;
logic [LINELEN/8-1:0] LineByteMask, DemuxedByteMask, FetchBufferByteSel;
logic [$clog2(LINELEN/8) - $clog2(MUXINTERVAL/8) - 1:0] WordOffsetAddr;
2022-12-23 07:58:14 +00:00
genvar index;
2022-02-03 15:36:11 +00:00
/////////////////////////////////////////////////////////////////////////////////////////////
// Read Path
/////////////////////////////////////////////////////////////////////////////////////////////
2022-11-29 16:52:40 +00:00
// Choose read address (CAdr). Normally use NextAdr, but use PAdr during stalls
// and FlushAdr when handling D$ flushes
// The icache must update to the newest PCNextF on flush as it is probably a trap. Trap
// sets PCNextF to XTVEC and the icache must start reading the instruction.
2023-01-07 23:39:13 +00:00
assign AdrSelMuxSel = {SelFlush, ((SelAdr | SelHPTW) & ~((DCACHE == 0) & FlushStage))};
mux3 #(SETLEN) AdrSelMux(NextAdr[SETTOP-1:OFFSETLEN], PAdr[SETTOP-1:OFFSETLEN], FlushAdr,
AdrSelMuxSel, CAdr);
2022-02-03 15:36:11 +00:00
// Array of cache ways, along with victim, hit, dirty, and read merging logic
2023-01-07 23:42:08 +00:00
cacheway #(NUMLINES, LINELEN, TAGLEN, OFFSETLEN, SETLEN, DCACHE) CacheWays[NUMWAYS-1:0](
.clk, .reset, .CacheEn, .CAdr, .PAdr, .LineWriteData, .LineByteMask,
2022-12-14 15:49:15 +00:00
.SetValid, .ClearValid, .SetDirty, .ClearDirty, .SelWriteback, .VictimWay,
.FlushWay, .SelFlush, .ReadDataLineWay, .HitWay, .ValidWay, .DirtyWay, .TagWay, .FlushStage, .InvalidateCache);
2023-01-07 23:42:08 +00:00
// Select victim way for associative caches
2022-01-05 16:01:03 +00:00
if(NUMWAYS > 1) begin:vict
cacheLRU #(NUMWAYS, SETLEN, OFFSETLEN, NUMLINES) cacheLRU(
2022-12-14 15:49:15 +00:00
.clk, .reset, .CacheEn, .FlushStage, .HitWay, .ValidWay, .VictimWay, .CAdr, .LRUWriteEn(LRUWriteEn & ~FlushStage),
2022-12-04 18:30:56 +00:00
.SetValid, .PAdr(PAdr[SETTOP-1:OFFSETLEN]), .InvalidateCache, .FlushCache);
2023-01-07 23:42:08 +00:00
end else
assign VictimWay = 1'b1; // one hot.
assign CacheHit = |HitWay;
assign LineDirty = |DirtyWay;
2022-02-03 16:52:22 +00:00
// ReadDataLineWay is a 2d array of cache line len by number of ways.
// Need to OR together each way in a bitwise manner.
// Final part of the AO Mux. First is the AND in the cacheway.
or_rows #(NUMWAYS, LINELEN) ReadDataAOMux(.a(ReadDataLineWay), .y(ReadDataLineCache));
or_rows #(NUMWAYS, TAGLEN) TagAOMux(.a(TagWay), .y(Tag));
2023-01-07 23:42:08 +00:00
// Data cache needs to choose word offset from PAdr or BeatCount to writeback dirty lines
if(DCACHE)
mux2 #(LOGBWPL) WordAdrrMux(.d0(PAdr[$clog2(LINELEN/8) - 1 : $clog2(MUXINTERVAL/8)]),
.d1(BeatCount), .s(SelBusBeat),
2022-03-11 20:58:21 +00:00
.y(WordOffsetAddr));
2023-01-07 23:42:08 +00:00
else
assign WordOffsetAddr = PAdr[$clog2(LINELEN/8) - 1 : $clog2(MUXINTERVAL/8)];
2023-01-07 23:42:08 +00:00
// Bypass cache array to save a cycle when finishing a load miss
mux2 #(LINELEN) EarlyReturnMux(ReadDataLineCache, FetchBuffer, SelFetchBuffer, ReadDataLine);
2023-01-07 23:44:44 +00:00
// Select word from cache line
subcachelineread #(LINELEN, WORDLEN, MUXINTERVAL) subcachelineread(
2023-01-07 23:44:44 +00:00
.PAdr(WordOffsetAddr), .ReadDataLine, .ReadDataWord);
// Bus address for fetch, writeback, or flush writeback
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));
2022-02-03 15:36:11 +00:00
/////////////////////////////////////////////////////////////////////////////////////////////
2023-01-07 23:44:44 +00:00
// Write Path
2022-02-03 15:36:11 +00:00
/////////////////////////////////////////////////////////////////////////////////////////////
2023-01-07 23:44:44 +00:00
// Adjust byte mask from word to cache line
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;
end
assign FetchBufferByteSel = SetValid & ~SetDirty ? '1 : ~DemuxedByteMask; // If load miss set all muxes to 1.
2022-12-14 15:34:29 +00:00
assign LineByteMask = SetValid ? '1 : SetDirty ? DemuxedByteMask : '0;
2023-01-07 23:44:44 +00:00
// Merge write data into fetched cache line for store miss
for(index = 0; index < LINELEN/8; index++) begin
mux2 #(8) WriteDataMux(.d0(CacheWriteData[(8*index)%WORDLEN+7:(8*index)%WORDLEN]),
.d1(FetchBuffer[8*index+7:8*index]), .s(FetchBufferByteSel[index]), .y(LineWriteData[8*index+7:8*index]));
end
2023-01-07 23:44:44 +00:00
2022-02-03 15:36:11 +00:00
/////////////////////////////////////////////////////////////////////////////////////////////
2023-01-07 23:46:23 +00:00
// Flush logic
2022-02-03 15:36:11 +00:00
/////////////////////////////////////////////////////////////////////////////////////////////
2023-01-07 23:46:23 +00:00
// Flush address (line number)
assign ResetOrFlushCntRst = reset | FlushCntRst;
2023-01-07 23:46:23 +00:00
flopenr #(SETLEN) FlushAdrReg(clk, ResetOrFlushCntRst, FlushAdrCntEn, FlushAdrP1, NextFlushAdr);
mux2 #(SETLEN) FlushAdrMux(NextFlushAdr, FlushAdrP1, FlushAdrCntEn, FlushAdr);
assign FlushAdrP1 = NextFlushAdr + 1'b1;
2023-01-07 23:39:13 +00:00
assign FlushAdrFlag = (NextFlushAdr == FLUSHADRTHRESHOLD[SETLEN-1:0]);
2023-01-07 23:46:23 +00:00
2023-01-07 23:49:18 +00:00
// Flush way
flopenl #(NUMWAYS) FlushWayReg(clk, FlushWayCntEn, ResetOrFlushCntRst, {{NUMWAYS-1{1'b0}}, 1'b1}, NextFlushWay, FlushWay);
2022-12-23 07:58:14 +00:00
if(NUMWAYS > 1) assign NextFlushWay = {FlushWay[NUMWAYS-2:0], FlushWay[NUMWAYS-1]};
2023-01-07 23:49:18 +00:00
else assign NextFlushWay = FlushWay[NUMWAYS-1];
assign FlushWayFlag = FlushWay[NUMWAYS-1];
2022-02-03 15:36:11 +00:00
/////////////////////////////////////////////////////////////////////////////////////////////
// Cache FSM
/////////////////////////////////////////////////////////////////////////////////////////////
2023-01-07 23:44:44 +00:00
cachefsm cachefsm(.clk, .reset, .CacheBusRW, .CacheBusAck,
.FlushStage, .CacheRW, .CacheAtomic, .Stall,
2022-12-04 22:09:09 +00:00
.CacheHit, .LineDirty, .CacheStall, .CacheCommitted,
2022-02-12 04:23:47 +00:00
.CacheMiss, .CacheAccess, .SelAdr,
2023-01-07 23:44:44 +00:00
.ClearValid, .ClearDirty, .SetDirty, .SetValid, .SelWriteback, .SelFlush,
.FlushAdrCntEn, .FlushWayCntEn, .FlushCntRst,
.FlushAdrFlag, .FlushWayFlag, .FlushCache, .SelFetchBuffer,
2023-01-07 23:44:44 +00:00
.InvalidateCache, .CacheEn, .LRUWriteEn);
2022-02-03 15:36:11 +00:00
endmodule