cvw/pipelined/src/cache/cache.sv

189 lines
9.4 KiB
Systemverilog
Raw Normal View History

///////////////////////////////////////////
// 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
//
// 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:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// 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.
////////////////////////////////////////////////////////////////////////////////////////////////
`include "wally-config.vh"
2022-02-03 15:36:11 +00:00
module cache #(parameter LINELEN, NUMLINES, NUMWAYS, DCACHE = 1) (
input logic clk,
input logic reset,
// cpu side
input logic CPUBusy,
input logic [1:0] RW,
input logic [1:0] Atomic,
input logic FlushCache,
input logic InvalidateCacheM,
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 [`XLEN-1:0] FinalWriteData,
output logic CacheCommitted,
output logic CacheStall,
2022-01-06 04:37:53 +00:00
// to performance counters to cpu
output logic CacheMiss,
output logic CacheAccess,
output logic save, restore,
2022-01-06 04:37:53 +00:00
// lsu control
input logic IgnoreRequestTLB,
input logic IgnoreRequestTrapM,
2022-01-06 04:37:53 +00:00
// Bus fsm interface
output logic CacheFetchLine,
output logic CacheWriteLine,
input logic CacheBusAck,
output logic [`PA_BITS-1:0] CacheBusAdr,
2022-02-13 21:06:18 +00:00
input logic [LINELEN-1:0] CacheBusWriteData,
output logic [LINELEN-1:0] ReadDataLine);
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;
localparam WORDSPERLINE = LINELEN/`XLEN;
localparam FlushAdrThreshold = NUMLINES - 1;
logic SelAdr;
2022-02-10 01:29:15 +00:00
logic [SETLEN-1:0] RAdr;
2022-02-10 16:43:37 +00:00
logic [LINELEN-1:0] CacheWriteData;
logic ClearValid;
logic ClearDirty;
2022-02-10 01:29:15 +00:00
logic [LINELEN-1:0] ReadDataLineWay [NUMWAYS-1:0];
2022-02-13 21:47:27 +00:00
logic [NUMWAYS-1:0] HitWay, HitWaySaved, HitWayFinal;
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-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-02-12 05:10:58 +00:00
.s({SelFlush, SelAdr}), .y(RAdr));
2022-02-03 15:36:11 +00:00
// Array of cache ways, along with victim, hit, dirty, and read merging logic
cacheway #(NUMLINES, LINELEN, TAGLEN, OFFSETLEN, SETLEN) CacheWays[NUMWAYS-1:0](
2022-02-13 21:53:01 +00:00
.clk, .reset, .RAdr, .PAdr, .CacheWriteData,
2022-02-10 17:40:10 +00:00
.SetValidWay, .ClearValidWay, .SetDirtyWay, .ClearDirtyWay, .SelEvict, .VictimWay,
2022-02-13 21:47:27 +00:00
.FlushWay, .SelFlush, .ReadDataLineWay, .HitWay, .VictimDirtyWay, .VictimTagWay,
.Invalidate(InvalidateCacheM));
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-02-13 21:47:27 +00:00
.clk, .reset, .HitWay(HitWayFinal), .VictimWay, .PAdr, .RAdr, .LRUWriteEn);
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;
assign VictimDirty = | VictimDirtyWay;
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.
2022-02-04 20:35:12 +00:00
or_rows #(NUMWAYS, LINELEN) ReadDataAOMux(.a(ReadDataLineWay), .y(ReadDataLine));
2022-02-04 20:18:10 +00:00
or_rows #(NUMWAYS, TAGLEN) VictimTagAOMux(.a(VictimTagWay), .y(VictimTag));
2022-02-04 20:18:10 +00:00
// Because of the sram clocked read when the ieu is stalled the read data maybe lost.
// There are two ways to resolve. 1. We can replay the read of the sram or we can save
// the data. Replay is eaiser but creates a longer critical path.
// save/restore only wayhit and readdata.
if(!`REPLAY) begin
2022-02-13 21:47:27 +00:00
flopenr #(NUMWAYS) wayhitsavereg(clk, save, reset, HitWay, HitWaySaved);
mux2 #(NUMWAYS) saverestoremux(HitWay, HitWaySaved, restore, HitWayFinal);
end else assign HitWayFinal = HitWay;
2022-02-04 20:18:10 +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
/////////////////////////////////////////////////////////////////////////////////////////////
mux2 #(LINELEN) WriteDataMux(.d0({WORDSPERLINE{FinalWriteData}}),
2022-02-13 21:06:18 +00:00
.d1(CacheBusWriteData), .s(SetValid), .y(CacheWriteData));
2022-02-03 15:36:11 +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));
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];
assign NextFlushWay = {FlushWay[NUMWAYS-2:0], FlushWay[NUMWAYS-1]};
2022-02-08 23:52:09 +00:00
/////////////////////////////////////////////////////////////////////////////////////////////
// Write Path: Write Enables
/////////////////////////////////////////////////////////////////////////////////////////////
2022-02-13 21:47:27 +00:00
mux3 #(NUMWAYS) selectwaymux(HitWayFinal, VictimWay, FlushWay,
2022-02-13 21:06:18 +00:00
{SelFlush, SetValid}, SelectedWay);
assign SetValidWay = SetValid ? SelectedWay : '0;
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-03 15:36:11 +00:00
/////////////////////////////////////////////////////////////////////////////////////////////
// Cache FSM
/////////////////////////////////////////////////////////////////////////////////////////////
cachefsm cachefsm(.clk, .reset, .CacheFetchLine, .CacheWriteLine, .CacheBusAck,
.RW, .Atomic, .CPUBusy, .IgnoreRequestTLB, .IgnoreRequestTrapM,
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,
.FlushWayCntRst, .FlushAdrFlag, .FlushWayFlag, .FlushCache,
.save, .restore,
2022-02-08 03:59:18 +00:00
.LRUWriteEn);
2022-02-03 15:36:11 +00:00
endmodule