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
|
|
|
|
//
|
|
|
|
// 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"
|
|
|
|
|
|
|
|
module cache #(parameter integer LINELEN,
|
|
|
|
parameter integer NUMLINES,
|
|
|
|
parameter integer NUMWAYS,
|
|
|
|
parameter integer DCACHE = 1)
|
|
|
|
(input logic clk,
|
2022-01-05 22:57:22 +00:00
|
|
|
input logic reset,
|
|
|
|
input logic CPUBusy,
|
2022-01-05 05:40:37 +00:00
|
|
|
// cpu side
|
2022-01-05 22:57:22 +00:00
|
|
|
input logic [1:0] RW,
|
|
|
|
input logic [1:0] Atomic,
|
|
|
|
input logic FlushCache,
|
|
|
|
input logic [11:0] LsuAdrE, // virtual address, but we only use the lower 12 bits.
|
2022-01-05 05:40:37 +00:00
|
|
|
input logic [`PA_BITS-1:0] LsuPAdrM, // physical address
|
2022-01-05 22:57:22 +00:00
|
|
|
input logic [11:0] PreLsuPAdrM, // physical or virtual address
|
|
|
|
input logic [`XLEN-1:0] FinalWriteData,
|
|
|
|
output logic [`XLEN-1:0] ReadDataWord,
|
|
|
|
output logic CacheCommitted,
|
2022-01-05 05:40:37 +00:00
|
|
|
|
|
|
|
// Bus fsm interface
|
2022-01-05 22:57:22 +00:00
|
|
|
input logic IgnoreRequest,
|
|
|
|
output logic CacheFetchLine,
|
|
|
|
output logic CacheWriteLine,
|
2022-01-05 05:40:37 +00:00
|
|
|
|
2022-01-05 22:57:22 +00:00
|
|
|
input logic CacheBusAck,
|
2022-01-05 05:52:42 +00:00
|
|
|
output logic [`PA_BITS-1:0] CacheBusAdr,
|
2022-01-05 05:40:37 +00:00
|
|
|
|
|
|
|
|
2022-01-05 05:52:42 +00:00
|
|
|
input logic [LINELEN-1:0] CacheMemWriteData,
|
2022-01-05 22:57:22 +00:00
|
|
|
output logic [`XLEN-1:0] ReadDataLineSets [(LINELEN/`XLEN)-1:0],
|
2022-01-05 05:40:37 +00:00
|
|
|
|
2022-01-05 22:57:22 +00:00
|
|
|
output logic CacheStall,
|
2022-01-05 05:40:37 +00:00
|
|
|
|
|
|
|
// to performance counters
|
2022-01-05 22:57:22 +00:00
|
|
|
output logic CacheMiss,
|
|
|
|
output logic CacheAccess,
|
|
|
|
input logic InvalidateCacheM
|
2022-01-05 05:40:37 +00:00
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
localparam integer LINEBYTELEN = LINELEN/8;
|
|
|
|
localparam integer OFFSETLEN = $clog2(LINEBYTELEN);
|
|
|
|
localparam integer INDEXLEN = $clog2(NUMLINES);
|
|
|
|
localparam integer TAGLEN = `PA_BITS - OFFSETLEN - INDEXLEN;
|
|
|
|
localparam integer WORDSPERLINE = LINELEN/`XLEN;
|
|
|
|
localparam integer LOGWPL = $clog2(WORDSPERLINE);
|
|
|
|
localparam integer LOGXLENBYTES = $clog2(`XLEN/8);
|
|
|
|
|
2022-01-05 22:57:22 +00:00
|
|
|
localparam integer FlushAdrThreshold = NUMLINES - 1;
|
2022-01-05 05:40:37 +00:00
|
|
|
|
2022-01-05 20:14:01 +00:00
|
|
|
logic [1:0] SelAdr;
|
2022-01-05 05:40:37 +00:00
|
|
|
logic [INDEXLEN-1:0] RAdr;
|
|
|
|
logic [LINELEN-1:0] SRAMWriteData;
|
|
|
|
logic SetValid, ClearValid;
|
|
|
|
logic SetDirty, ClearDirty;
|
|
|
|
logic [LINELEN-1:0] ReadDataLineWayMasked [NUMWAYS-1:0];
|
|
|
|
logic [NUMWAYS-1:0] WayHit;
|
|
|
|
logic CacheHit;
|
|
|
|
logic [LINELEN-1:0] ReadDataLineM;
|
|
|
|
logic [WORDSPERLINE-1:0] SRAMWordEnable;
|
|
|
|
|
|
|
|
logic SRAMWordWriteEnableM;
|
|
|
|
logic SRAMLineWriteEnableM;
|
|
|
|
logic [NUMWAYS-1:0] SRAMLineWayWriteEnableM;
|
|
|
|
logic [NUMWAYS-1:0] SRAMWayWriteEnable;
|
|
|
|
|
|
|
|
|
|
|
|
logic [NUMWAYS-1:0] VictimWay;
|
|
|
|
logic [NUMWAYS-1:0] VictimDirtyWay;
|
|
|
|
logic VictimDirty;
|
|
|
|
|
|
|
|
logic [2**LOGWPL-1:0] MemPAdrDecodedW;
|
|
|
|
|
|
|
|
logic [TAGLEN-1:0] VictimTagWay [NUMWAYS-1:0];
|
|
|
|
logic [TAGLEN-1:0] VictimTag;
|
|
|
|
|
|
|
|
logic [INDEXLEN-1:0] FlushAdr;
|
|
|
|
logic [INDEXLEN-1:0] FlushAdrP1;
|
|
|
|
logic FlushAdrCntEn;
|
|
|
|
logic FlushAdrCntRst;
|
|
|
|
logic FlushAdrFlag;
|
2022-01-05 22:57:22 +00:00
|
|
|
logic FlushWayFlag;
|
2022-01-05 05:40:37 +00:00
|
|
|
|
|
|
|
logic [NUMWAYS-1:0] FlushWay;
|
|
|
|
logic [NUMWAYS-1:0] NextFlushWay;
|
|
|
|
logic FlushWayCntEn;
|
|
|
|
logic FlushWayCntRst;
|
|
|
|
|
|
|
|
logic VDWriteEnable;
|
|
|
|
logic SelEvict;
|
|
|
|
logic LRUWriteEn;
|
|
|
|
logic [NUMWAYS-1:0] VDWriteEnableWay;
|
|
|
|
logic SelFlush;
|
|
|
|
|
|
|
|
// Read Path CPU (IEU) side
|
|
|
|
|
|
|
|
mux3 #(INDEXLEN)
|
|
|
|
AdrSelMux(.d0(LsuAdrE[INDEXLEN+OFFSETLEN-1:OFFSETLEN]),
|
|
|
|
.d1(PreLsuPAdrM[INDEXLEN+OFFSETLEN-1:OFFSETLEN]),
|
2022-01-05 22:57:22 +00:00
|
|
|
.d2(FlushAdr),
|
2022-01-05 20:14:01 +00:00
|
|
|
.s(SelAdr),
|
2022-01-05 05:40:37 +00:00
|
|
|
.y(RAdr));
|
2022-01-05 20:14:01 +00:00
|
|
|
|
2022-01-05 22:57:22 +00:00
|
|
|
|
|
|
|
|
2022-01-05 05:40:37 +00:00
|
|
|
cacheway #(.NUMLINES(NUMLINES), .LINELEN(LINELEN), .TAGLEN(TAGLEN),
|
|
|
|
.OFFSETLEN(OFFSETLEN), .INDEXLEN(INDEXLEN))
|
|
|
|
MemWay[NUMWAYS-1:0](.clk, .reset, .RAdr,
|
|
|
|
.PAdr(LsuPAdrM),
|
|
|
|
.WriteEnable(SRAMWayWriteEnable),
|
|
|
|
.VDWriteEnable(VDWriteEnableWay),
|
|
|
|
.WriteWordEnable(SRAMWordEnable),
|
|
|
|
.TagWriteEnable(SRAMLineWayWriteEnableM),
|
|
|
|
.WriteData(SRAMWriteData),
|
|
|
|
.SetValid, .ClearValid, .SetDirty, .ClearDirty, .SelEvict,
|
|
|
|
.VictimWay, .FlushWay, .SelFlush,
|
|
|
|
.ReadDataLineWayMasked,
|
|
|
|
.WayHit, .VictimDirtyWay, .VictimTagWay,
|
2022-01-05 05:52:42 +00:00
|
|
|
.InvalidateAll(InvalidateCacheM));
|
2022-01-05 05:40:37 +00:00
|
|
|
|
2022-01-05 16:01:03 +00:00
|
|
|
if(NUMWAYS > 1) begin:vict
|
|
|
|
cachereplacementpolicy #(NUMWAYS, INDEXLEN, OFFSETLEN, NUMLINES)
|
|
|
|
cachereplacementpolicy(.clk, .reset,
|
|
|
|
.WayHit,
|
|
|
|
.VictimWay,
|
|
|
|
.LsuPAdrM(LsuPAdrM[INDEXLEN+OFFSETLEN-1:OFFSETLEN]),
|
|
|
|
.RAdr,
|
|
|
|
.LRUWriteEn);
|
|
|
|
end else begin:vict
|
|
|
|
assign VictimWay = 1'b1; // one hot.
|
|
|
|
end
|
2022-01-05 05:40:37 +00:00
|
|
|
|
|
|
|
assign CacheHit = | WayHit;
|
|
|
|
assign VictimDirty = | VictimDirtyWay;
|
|
|
|
|
|
|
|
|
|
|
|
// ReadDataLineWayMaskedM 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(ReadDataLineWayMasked), .y(ReadDataLineM));
|
|
|
|
or_rows #(NUMWAYS, TAGLEN) VictimTagAOMux(.a(VictimTagWay), .y(VictimTag));
|
|
|
|
|
|
|
|
|
|
|
|
// Convert the Read data bus ReadDataSelectWay into sets of XLEN so we can
|
|
|
|
// easily build a variable input mux.
|
|
|
|
// *** consider using a limited range shift to do this final muxing.
|
|
|
|
genvar index;
|
2022-01-05 16:01:03 +00:00
|
|
|
if(DCACHE == 1) begin: readdata
|
|
|
|
for (index = 0; index < WORDSPERLINE; index++) begin:readdatalinesetsmux
|
|
|
|
assign ReadDataLineSets[index] = ReadDataLineM[((index+1)*`XLEN)-1: (index*`XLEN)];
|
|
|
|
end
|
2022-01-05 05:40:37 +00:00
|
|
|
// variable input mux
|
2022-01-05 05:52:42 +00:00
|
|
|
assign ReadDataWord = ReadDataLineSets[LsuPAdrM[LOGWPL + LOGXLENBYTES - 1 : LOGXLENBYTES]];
|
2022-01-05 16:01:03 +00:00
|
|
|
end else begin: readdata
|
2022-01-05 05:40:37 +00:00
|
|
|
logic [31:0] ReadLineSetsF [LINELEN/16-1:0];
|
|
|
|
logic [31:0] FinalInstrRawF;
|
2022-01-05 16:01:03 +00:00
|
|
|
for(index = 0; index < LINELEN / 16 - 1; index++)
|
|
|
|
assign ReadLineSetsF[index] = ReadDataLineM[((index+1)*16)+16-1 : (index*16)];
|
2022-01-05 05:40:37 +00:00
|
|
|
assign ReadLineSetsF[LINELEN/16-1] = {16'b0, ReadDataLineM[LINELEN-1:LINELEN-16]};
|
|
|
|
assign FinalInstrRawF = ReadLineSetsF[LsuPAdrM[$clog2(LINELEN / 32) + 1 : 1]];
|
2022-01-05 16:01:03 +00:00
|
|
|
if (`XLEN == 64) assign ReadDataWord = {32'b0, FinalInstrRawF};
|
|
|
|
else assign ReadDataWord = FinalInstrRawF;
|
2022-01-05 05:40:37 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
// Write Path CPU (IEU) side
|
|
|
|
|
|
|
|
onehotdecoder #(LOGWPL)
|
|
|
|
adrdec(.bin(LsuPAdrM[LOGWPL+LOGXLENBYTES-1:LOGXLENBYTES]),
|
|
|
|
.decoded(MemPAdrDecodedW));
|
|
|
|
|
|
|
|
assign SRAMWordEnable = SRAMLineWriteEnableM ? '1 : MemPAdrDecodedW;
|
|
|
|
|
|
|
|
assign SRAMLineWayWriteEnableM = SRAMLineWriteEnableM ? VictimWay : '0;
|
|
|
|
|
|
|
|
mux2 #(NUMWAYS) WriteEnableMux(.d0(SRAMWordWriteEnableM ? WayHit : '0),
|
|
|
|
.d1(SRAMLineWayWriteEnableM),
|
|
|
|
.s(SRAMLineWriteEnableM),
|
|
|
|
.y(SRAMWayWriteEnable));
|
|
|
|
|
|
|
|
|
|
|
|
|
2022-01-05 05:52:42 +00:00
|
|
|
mux2 #(LINELEN) WriteDataMux(.d0({WORDSPERLINE{FinalWriteData}}),
|
|
|
|
.d1(CacheMemWriteData),
|
2022-01-05 05:40:37 +00:00
|
|
|
.s(SRAMLineWriteEnableM),
|
|
|
|
.y(SRAMWriteData));
|
|
|
|
|
|
|
|
|
|
|
|
mux3 #(`PA_BITS) BaseAdrMux(.d0({LsuPAdrM[`PA_BITS-1:OFFSETLEN], {{OFFSETLEN}{1'b0}}}),
|
|
|
|
.d1({VictimTag, LsuPAdrM[INDEXLEN+OFFSETLEN-1:OFFSETLEN], {{OFFSETLEN}{1'b0}}}),
|
2022-01-05 22:57:22 +00:00
|
|
|
.d2({VictimTag, FlushAdr, {{OFFSETLEN}{1'b0}}}),
|
2022-01-05 05:40:37 +00:00
|
|
|
.s({SelFlush, SelEvict}),
|
2022-01-05 05:52:42 +00:00
|
|
|
.y(CacheBusAdr));
|
2022-01-05 05:40:37 +00:00
|
|
|
|
|
|
|
|
|
|
|
// flush address and way generation.
|
|
|
|
// increment on 2nd to last way
|
|
|
|
flopenr #(INDEXLEN)
|
|
|
|
FlushAdrReg(.clk,
|
|
|
|
.reset(reset | FlushAdrCntRst),
|
2022-01-05 22:57:22 +00:00
|
|
|
.en(FlushAdrCntEn),
|
2022-01-05 05:40:37 +00:00
|
|
|
.d(FlushAdrP1),
|
|
|
|
.q(FlushAdr));
|
|
|
|
assign FlushAdrP1 = FlushAdr + 1'b1;
|
|
|
|
|
|
|
|
|
|
|
|
flopenl #(NUMWAYS)
|
|
|
|
FlushWayReg(.clk,
|
|
|
|
.load(reset | FlushWayCntRst),
|
|
|
|
.en(FlushWayCntEn),
|
|
|
|
.val({{NUMWAYS-1{1'b0}}, 1'b1}),
|
|
|
|
.d(NextFlushWay),
|
|
|
|
.q(FlushWay));
|
|
|
|
|
|
|
|
assign VDWriteEnableWay = FlushWay & {NUMWAYS{VDWriteEnable}};
|
|
|
|
|
|
|
|
assign NextFlushWay = {FlushWay[NUMWAYS-2:0], FlushWay[NUMWAYS-1]};
|
|
|
|
|
2022-01-05 22:57:22 +00:00
|
|
|
//assign FlushAdrFlag = FlushAdr == FlushAdrThreshold[INDEXLEN-1:0] & FlushWay[NUMWAYS-1];
|
|
|
|
assign FlushAdrFlag = FlushAdr == FlushAdrThreshold[INDEXLEN-1:0];
|
|
|
|
assign FlushWayFlag = FlushWay[NUMWAYS-1];
|
2022-01-05 05:40:37 +00:00
|
|
|
|
|
|
|
// controller
|
2022-01-05 05:52:42 +00:00
|
|
|
// *** fixme
|
2022-01-05 05:40:37 +00:00
|
|
|
logic CacheableM;
|
|
|
|
|
|
|
|
assign CacheableM = 1;
|
|
|
|
|
2022-01-05 05:52:42 +00:00
|
|
|
|
|
|
|
cachefsm cachefsm(.clk, .reset, .CacheFetchLine, .CacheWriteLine, .CacheBusAck,
|
|
|
|
.RW, .Atomic, .CPUBusy, .CacheableM, .IgnoreRequest,
|
|
|
|
.CacheHit, .VictimDirty, .CacheStall, .CacheCommitted,
|
2022-01-05 20:14:01 +00:00
|
|
|
.CacheMiss, .CacheAccess, .SelAdr, .SetValid,
|
2022-01-05 05:52:42 +00:00
|
|
|
.ClearValid, .SetDirty, .ClearDirty, .SRAMWordWriteEnableM,
|
|
|
|
.SRAMLineWriteEnableM, .SelEvict, .SelFlush,
|
|
|
|
.FlushAdrCntEn, .FlushWayCntEn, .FlushAdrCntRst,
|
2022-01-05 22:57:22 +00:00
|
|
|
.FlushWayCntRst, .FlushAdrFlag, .FlushWayFlag, .FlushCache,
|
2022-01-05 05:52:42 +00:00
|
|
|
.VDWriteEnable, .LRUWriteEn);
|
2022-01-05 05:40:37 +00:00
|
|
|
|
|
|
|
|
|
|
|
endmodule // dcache
|