Merge pull request #206 from AlecVercruysse/coverage2

i$ coverage improvements
This commit is contained in:
Ross Thompson 2023-04-05 17:29:35 -05:00 committed by GitHub
commit 7cdd12a40a
6 changed files with 167 additions and 39 deletions

36
src/cache/cache.sv vendored
View File

@ -76,7 +76,7 @@ module cache #(parameter LINELEN, NUMLINES, NUMWAYS, LOGBWPL, WORDLEN, MUXINTE
logic [1:0] AdrSelMuxSel;
logic [SETLEN-1:0] CacheSet;
logic [LINELEN-1:0] LineWriteData;
logic ClearValid, ClearDirty, SetDirty, SetValid;
logic ClearDirty, SetDirty, SetValid;
logic [LINELEN-1:0] ReadDataLineWay [NUMWAYS-1:0];
logic [NUMWAYS-1:0] HitWay, ValidWay;
logic CacheHit;
@ -116,7 +116,7 @@ module cache #(parameter LINELEN, NUMLINES, NUMWAYS, LOGBWPL, WORDLEN, MUXINTE
// Array of cache ways, along with victim, hit, dirty, and read merging logic
cacheway #(NUMLINES, LINELEN, TAGLEN, OFFSETLEN, SETLEN, READ_ONLY_CACHE) CacheWays[NUMWAYS-1:0](
.clk, .reset, .CacheEn, .CacheSet, .PAdr, .LineWriteData, .LineByteMask,
.SetValid, .ClearValid, .SetDirty, .ClearDirty, .SelWriteback, .VictimWay,
.SetValid, .SetDirty, .ClearDirty, .SelWriteback, .VictimWay,
.FlushWay, .SelFlush, .ReadDataLineWay, .HitWay, .ValidWay, .DirtyWay, .TagWay, .FlushStage, .InvalidateCache);
// Select victim way for associative caches
@ -188,19 +188,25 @@ module cache #(parameter LINELEN, NUMLINES, NUMWAYS, LOGBWPL, WORDLEN, MUXINTE
// Flush logic
/////////////////////////////////////////////////////////////////////////////////////////////
// Flush address (line number)
assign ResetOrFlushCntRst = reset | FlushCntRst;
flopenr #(SETLEN) FlushAdrReg(clk, ResetOrFlushCntRst, FlushAdrCntEn, FlushAdrP1, NextFlushAdr);
mux2 #(SETLEN) FlushAdrMux(NextFlushAdr, FlushAdrP1, FlushAdrCntEn, FlushAdr);
assign FlushAdrP1 = NextFlushAdr + 1'b1;
assign FlushAdrFlag = (NextFlushAdr == FLUSHADRTHRESHOLD[SETLEN-1:0]);
// Flush way
flopenl #(NUMWAYS) FlushWayReg(clk, FlushWayCntEn, ResetOrFlushCntRst, {{NUMWAYS-1{1'b0}}, 1'b1}, NextFlushWay, FlushWay);
if(NUMWAYS > 1) assign NextFlushWay = {FlushWay[NUMWAYS-2:0], FlushWay[NUMWAYS-1]};
else assign NextFlushWay = FlushWay[NUMWAYS-1];
assign FlushWayFlag = FlushWay[NUMWAYS-1];
if (!READ_ONLY_CACHE) begin:flushlogic
// Flush address (line number)
assign ResetOrFlushCntRst = reset | FlushCntRst;
flopenr #(SETLEN) FlushAdrReg(clk, ResetOrFlushCntRst, FlushAdrCntEn, FlushAdrP1, NextFlushAdr);
mux2 #(SETLEN) FlushAdrMux(NextFlushAdr, FlushAdrP1, FlushAdrCntEn, FlushAdr);
assign FlushAdrP1 = NextFlushAdr + 1'b1;
assign FlushAdrFlag = (NextFlushAdr == FLUSHADRTHRESHOLD[SETLEN-1:0]);
// Flush way
flopenl #(NUMWAYS) FlushWayReg(clk, FlushWayCntEn, ResetOrFlushCntRst, {{NUMWAYS-1{1'b0}}, 1'b1}, NextFlushWay, FlushWay);
if(NUMWAYS > 1) assign NextFlushWay = {FlushWay[NUMWAYS-2:0], FlushWay[NUMWAYS-1]};
else assign NextFlushWay = FlushWay[NUMWAYS-1];
assign FlushWayFlag = FlushWay[NUMWAYS-1];
end // block: flushlogic
else begin:flushlogic
assign FlushWayFlag = 0;
assign FlushAdrFlag = 0;
end
/////////////////////////////////////////////////////////////////////////////////////////////
// Cache FSM
/////////////////////////////////////////////////////////////////////////////////////////////
@ -209,7 +215,7 @@ module cache #(parameter LINELEN, NUMLINES, NUMWAYS, LOGBWPL, WORDLEN, MUXINTE
.FlushStage, .CacheRW, .CacheAtomic, .Stall,
.CacheHit, .LineDirty, .CacheStall, .CacheCommitted,
.CacheMiss, .CacheAccess, .SelAdr,
.ClearValid, .ClearDirty, .SetDirty, .SetValid, .SelWriteback, .SelFlush,
.ClearDirty, .SetDirty, .SetValid, .SelWriteback, .SelFlush,
.FlushAdrCntEn, .FlushWayCntEn, .FlushCntRst,
.FlushAdrFlag, .FlushWayFlag, .FlushCache, .SelFetchBuffer,
.InvalidateCache, .CacheEn, .LRUWriteEn);

View File

@ -67,11 +67,15 @@ module cacheLRU
assign AllValid = &ValidWay;
///// Update replacement bits.
// coverage off
// Excluded from coverage b/c it is untestable without varying NUMWAYS.
function integer log2 (integer value);
for (log2=0; value>0; log2=log2+1)
value = value>>1;
return log2;
endfunction // log2
// coverage on
// On a miss we need to ignore HitWay and derive the new replacement bits with the VictimWay.
mux2 #(NUMWAYS) WayMux(HitWay, VictimWay, SetValid, Way);

View File

@ -55,7 +55,6 @@ module cachefsm #(parameter READ_ONLY_CACHE = 0) (
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 ClearValid, // Clear the valid bit in the selected way and set
output logic SetValid, // Set the dirty bit in the selected way and set
output logic ClearDirty, // Clear the dirty bit in the selected way and set
output logic SetDirty, // Set the dirty bit in the selected way and set
@ -146,7 +145,6 @@ module cachefsm #(parameter READ_ONLY_CACHE = 0) (
assign SetValid = CurrState == STATE_WRITE_LINE;
assign SetDirty = (CurrState == STATE_READY & AnyUpdateHit) |
(CurrState == STATE_WRITE_LINE & (StoreAMO));
assign ClearValid = '0;
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.
assign LRUWriteEn = (CurrState == STATE_READY & AnyHit) |

57
src/cache/cacheway.sv vendored
View File

@ -38,8 +38,7 @@ module cacheway #(parameter NUMLINES=512, LINELEN = 256, TAGLEN = 26,
input logic [$clog2(NUMLINES)-1:0] CacheSet, // Cache address, the output of the address select mux, NextAdr, PAdr, or FlushAdr
input logic [`PA_BITS-1:0] PAdr, // Physical address
input logic [LINELEN-1:0] LineWriteData, // Final data written to cache (D$ only)
input logic SetValid, // Set the dirty bit in the selected way and set
input logic ClearValid, // Clear the valid bit in the selected way and set
input logic SetValid, // Set the valid bit in the selected way and set
input logic SetDirty, // Set the dirty bit in the selected way and set
input logic ClearDirty, // Clear the dirty bit in the selected way and set
input logic SelWriteback, // Overrides cached tag check to select a specific way and set for writeback
@ -71,22 +70,26 @@ module cacheway #(parameter NUMLINES=512, LINELEN = 256, TAGLEN = 26,
logic [LINELEN/8-1:0] FinalByteMask;
logic SetValidEN;
logic SetValidWay;
logic ClearValidWay;
logic SetDirtyWay;
logic ClearDirtyWay;
logic SelNonHit;
logic SelData;
logic FlushWayEn, VictimWayEn;
// FlushWay and VictimWay are part of a one hot way selection. Must clear them if FlushWay not selected
// or VictimWay not selected.
assign FlushWayEn = FlushWay & SelFlush;
assign VictimWayEn = VictimWay & SelWriteback;
assign SelNonHit = FlushWayEn | SetValid | SelWriteback;
mux2 #(1) seltagmux(VictimWay, FlushWay, SelFlush, SelTag);
if (!READ_ONLY_CACHE) begin:flushlogic
logic FlushWayEn;
mux2 #(1) seltagmux(VictimWay, FlushWay, SelFlush, SelTag);
// FlushWay is part of a one hot way selection. Must clear it if FlushWay not selected.
assign FlushWayEn = FlushWay & SelFlush;
assign SelNonHit = FlushWayEn | SetValid | SelWriteback;
end
else begin:flushlogic // no flush operation for read-only caches.
assign SelTag = VictimWay;
assign SelNonHit = SetValid;
end
mux2 #(1) selectedwaymux(HitWay, SelTag, SelNonHit , SelData);
/////////////////////////////////////////////////////////////////////////////////////////////
@ -94,12 +97,16 @@ module cacheway #(parameter NUMLINES=512, LINELEN = 256, TAGLEN = 26,
/////////////////////////////////////////////////////////////////////////////////////////////
assign SetValidWay = SetValid & SelData;
assign ClearValidWay = ClearValid & SelData;
assign SetDirtyWay = SetDirty & SelData;
assign ClearDirtyWay = ClearDirty & SelData;
if (!READ_ONLY_CACHE) begin
assign SetDirtyWay = SetDirty & SelData;
assign SelectedWriteWordEn = (SetValidWay | SetDirtyWay) & ~FlushStage;
end
else begin
assign SelectedWriteWordEn = SetValidWay & ~FlushStage;
end
// If writing the whole line set all write enables to 1, else only set the correct word.
assign SelectedWriteWordEn = (SetValidWay | SetDirtyWay) & ~FlushStage;
assign FinalByteMask = SetValidWay ? '1 : LineByteMask; // OR
assign SetValidEN = SetValidWay & ~FlushStage;
@ -107,8 +114,8 @@ module cacheway #(parameter NUMLINES=512, LINELEN = 256, TAGLEN = 26,
// Tag Array
/////////////////////////////////////////////////////////////////////////////////////////////
ram1p1rwbe #(.DEPTH(NUMLINES), .WIDTH(TAGLEN)) CacheTagMem(.clk, .ce(CacheEn),
.addr(CacheSet), .dout(ReadTag), .bwe('1),
ram1p1rwe #(.DEPTH(NUMLINES), .WIDTH(TAGLEN)) CacheTagMem(.clk, .ce(CacheEn),
.addr(CacheSet), .dout(ReadTag),
.din(PAdr[`PA_BITS-1:OFFSETLEN+INDEXLEN]), .we(SetValidEN));
// AND portion of distributed tag multiplexer
@ -128,10 +135,18 @@ module cacheway #(parameter NUMLINES=512, LINELEN = 256, TAGLEN = 26,
localparam LOGNUMSRAM = $clog2(NUMSRAM);
for(words = 0; words < NUMSRAM; words++) begin: word
ram1p1rwbe #(.DEPTH(NUMLINES), .WIDTH(SRAMLEN)) CacheDataMem(.clk, .ce(CacheEn), .addr(CacheSet),
if (!READ_ONLY_CACHE) begin:wordram
ram1p1rwbe #(.DEPTH(NUMLINES), .WIDTH(SRAMLEN)) CacheDataMem(.clk, .ce(CacheEn), .addr(CacheSet),
.dout(ReadDataLine[SRAMLEN*(words+1)-1:SRAMLEN*words]),
.din(LineWriteData[SRAMLEN*(words+1)-1:SRAMLEN*words]),
.we(SelectedWriteWordEn), .bwe(FinalByteMask[SRAMLENINBYTES*(words+1)-1:SRAMLENINBYTES*words]));
end
else begin:wordram // no byte-enable needed for i$.
ram1p1rwe #(.DEPTH(NUMLINES), .WIDTH(SRAMLEN)) CacheDataMem(.clk, .ce(CacheEn), .addr(CacheSet),
.dout(ReadDataLine[SRAMLEN*(words+1)-1:SRAMLEN*words]),
.din(LineWriteData[SRAMLEN*(words+1)-1:SRAMLEN*words]),
.we(SelectedWriteWordEn));
end
end
// AND portion of distributed read multiplexers
@ -146,7 +161,7 @@ module cacheway #(parameter NUMLINES=512, LINELEN = 256, TAGLEN = 26,
if(CacheEn) begin
ValidWay <= #1 ValidBits[CacheSet];
if(InvalidateCache) ValidBits <= #1 '0;
else if (SetValidEN | (ClearValidWay & ~FlushStage)) ValidBits[CacheSet] <= #1 SetValidWay;
else if (SetValidEN) ValidBits[CacheSet] <= #1 SetValidWay;
end
end

View File

@ -0,0 +1,105 @@
///////////////////////////////////////////
// 1 port sram.
//
// Written: avercruysse@hmc.edu (Modified from ram1p1rwbe, by ross1728@gmail.com)
// Created: 04 April 2023
//
// Purpose: ram1p1wre, but without byte-enable. Used for icache data.
// Be careful using this module, since coverage is turned off for (ce & we).
// In read-only caches, we never get (we=1, ce=0), so this waiver is needed.
//
// Documentation:
//
// A component of the CORE-V-WALLY configurable RISC-V project.
//
// 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.
////////////////////////////////////////////////////////////////////////////////////////////////
// WIDTH is number of bits in one "word" of the memory, DEPTH is number of such words
`include "wally-config.vh"
module ram1p1rwe #(parameter DEPTH=64, WIDTH=44) (
input logic clk,
input logic ce,
input logic [$clog2(DEPTH)-1:0] addr,
input logic [WIDTH-1:0] din,
input logic we,
output logic [WIDTH-1:0] dout
);
logic [WIDTH-1:0] RAM[DEPTH-1:0];
// ***************************************************************************
// TRUE SRAM macro
// ***************************************************************************
if ((`USE_SRAM == 1) & (WIDTH == 128) & (DEPTH == 64)) begin // Cache data subarray
// 64 x 128-bit SRAM
ram1p1rwbe_64x128 sram1A (.CLK(clk), .CEB(~ce), .WEB(~we),
.A(addr), .D(din),
.BWEB('0), .Q(dout));
end else if ((`USE_SRAM == 1) & (WIDTH == 44) & (DEPTH == 64)) begin // RV64 cache tag
// 64 x 44-bit SRAM
ram1p1rwbe_64x44 sram1B (.CLK(clk), .CEB(~ce), .WEB(~we),
.A(addr), .D(din),
.BWEB('0), .Q(dout));
end else if ((`USE_SRAM == 1) & (WIDTH == 22) & (DEPTH == 64)) begin // RV32 cache tag
// 64 x 22-bit SRAM
ram1p1rwbe_64x22 sram1B (.CLK(clk), .CEB(~ce), .WEB(~we),
.A(addr), .D(din),
.BWEB('0), .Q(dout));
// ***************************************************************************
// READ first SRAM model
// ***************************************************************************
end else begin: ram
integer i;
// Read
logic [$clog2(DEPTH)-1:0] addrd;
flopen #($clog2(DEPTH)) adrreg(clk, ce, addr, addrd);
assign dout = RAM[addrd];
/* // Read
always_ff @(posedge clk)
if(ce) dout <= #1 mem[addr]; */
// Write divided into part for bytes and part for extra msbs
// Questa sim version 2022.3_2 does not allow multiple drivers for RAM when using always_ff.
// Therefore these always blocks use the older always @(posedge clk)
if(WIDTH >= 8)
always @(posedge clk)
// coverage off
// ce only goes low when cachefsm is in READY state and Flush is asserted.
// for read-only caches, we only goes high in the STATE_WRITE_LINE cachefsm state.
// so we can never get we=1, ce=0 for I$.
if (ce & we)
// coverage on
for(i = 0; i < WIDTH/8; i++)
RAM[addr][i*8 +: 8] <= #1 din[i*8 +: 8];
if (WIDTH%8 != 0) // handle msbs if width not a multiple of 8
always @(posedge clk)
// coverage off
// (see the above explanation)
if (ce & we)
// coverage on
RAM[addr][WIDTH-1:WIDTH-WIDTH%8] <= #1 din[WIDTH-1:WIDTH-WIDTH%8];
end
endmodule

View File

@ -724,7 +724,7 @@ module DCacheFlushFSM
// these dirty bit selections would be needed if dirty is moved inside the tag array.
//.dirty(testbench.dut.core.lsu.bus.dcache.dcache.CacheWays[way].dirty.DirtyMem.RAM[index]),
//.dirty(testbench.dut.core.lsu.bus.dcache.dcache.CacheWays[way].CacheTagMem.RAM[index][`PA_BITS+tagstart]),
.data(testbench.dut.core.lsu.bus.dcache.dcache.CacheWays[way].word[cacheWord].CacheDataMem.RAM[index]),
.data(testbench.dut.core.lsu.bus.dcache.dcache.CacheWays[way].word[cacheWord].wordram.CacheDataMem.RAM[index]),
.index(index),
.cacheWord(cacheWord),
.CacheData(CacheData[way][index][cacheWord]),