This commit is contained in:
Kevin Thomas 2023-04-05 15:04:12 -05:00
commit 7345927cb1
14 changed files with 478 additions and 95 deletions

4
.gitignore vendored
View File

@ -112,4 +112,6 @@ sim/results-error/
sim/test1.rep sim/test1.rep
sim/vsim.log sim/vsim.log
tests/coverage/*.elf tests/coverage/*.elf
*.elf.memfile *.elf.memfile
sim/*Cache.log
sim/branch

241
bin/CacheSim.py Executable file
View File

@ -0,0 +1,241 @@
#!/usr/bin/env python3
###########################################
## CacheSim.py
##
## Written: lserafini@hmc.edu
## Created: 27 March 2023
## Modified: 5 April 2023
##
## Purpose: Simulate a L1 D$ or I$ for comparison with Wally
##
## 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.
################################################################################################
# how to invoke this simulator:
# CacheSim.py <number of lines> <number of ways> <length of physical address> <length of tag> -f <log file> (-v)
# so the default invocation for rv64gc is 'CacheSim.py 64 4 56 44 -f <log file>'
# the log files to run this simulator on can be generated from testbench.sv
# by setting I_CACHE_ADDR_LOGGER and/or D_CACHE_ADDR_LOGGER to 1 before running tests.
# I (Lim) recommend logging a single set of tests (such as wally64priv) at a time.
# This helps avoid unexpected logger behavior.
# With verbose mode off, the simulator only reports mismatches between its and Wally's behavior.
# With verbose mode on, the simulator logs each access into the cache.
import sys
import math
import argparse
import os
class CacheLine:
def __init__(self):
self.tag = 0
self.valid = False
self.dirty = False
def __str__(self):
string = "(V: " + str(self.valid) + ", D: " + str(self.dirty)
string += ", Tag: " + str(hex(self.tag)) + ")"
return string
def __repr__(self):
return self.__str__()
class Cache:
def __init__(self, numsets, numways, addrlen, taglen):
self.numways = numways
self.numsets = numsets
self.addrlen = addrlen
self.taglen = taglen
self.setlen = int(math.log(numsets, 2))
self.offsetlen = self.addrlen - self.taglen - self.setlen
self.ways = []
for i in range(numways):
self.ways.append([])
for j in range(numsets):
self.ways[i].append(CacheLine())
self.pLRU = []
for i in range(self.numsets):
self.pLRU.append([0]*(self.numways-1))
# flushes the cache by setting all dirty bits to False
def flush(self):
for way in self.ways:
for line in way:
line.dirty = False
# invalidates the cache by setting all valid bits to False
def invalidate(self):
for way in self.ways:
for line in way:
line.valid = False
# resets the pLRU to a fresh 2-D array of 0s
def clear_pLRU(self):
self.pLRU = []
for i in range(self.numsets):
self.pLRU.append([0]*(self.numways-1))
# splits the given address into tag, set, and offset
def splitaddr(self, addr):
# no need for offset in the sim, but it's here for debug
tag = addr >> (self.setlen + self.offsetlen) & int('1'*self.taglen, 2)
setnum = (addr >> self.offsetlen) & int('1'*self.setlen, 2)
offset = addr & int('1'*self.offsetlen, 2)
return tag, setnum, offset
# performs a cache access with the given address.
# returns a character representing the outcome:
# H/M/E/D - hit, miss, eviction, or eviction with writeback
def cacheaccess(self, addr, write=False):
tag, setnum, _ = self.splitaddr(addr)
# check our ways to see if we have a hit
for waynum in range(self.numways):
line = self.ways[waynum][setnum]
if line.tag == tag and line.valid:
line.dirty = line.dirty or write
self.update_pLRU(waynum, setnum)
return 'H'
# we didn't hit, but we may not need to evict.
# check for an empty way line.
for waynum in range(self.numways):
line = self.ways[waynum][setnum]
if not line.valid:
line.tag = tag
line.valid = True
line.dirty = write
self.update_pLRU(waynum, setnum)
return 'M'
# we need to evict. Select a victim and overwrite.
victim = self.getvictimway(setnum)
line = self.ways[victim][setnum]
prevdirty = line.dirty
line.tag = tag
line.valid = True # technically redundant
line.dirty = write
self.update_pLRU(victim, setnum)
return 'D' if prevdirty else 'E'
# updates the psuedo-LRU tree for the given set
# with an access to the given way
def update_pLRU(self, waynum, setnum):
if self.numways == 1:
return
tree = self.pLRU[setnum]
bottomrow = (self.numways - 1)//2
index = (waynum // 2) + bottomrow
tree[index] = int(not (waynum % 2))
while index > 0:
parent = (index-1) // 2
tree[parent] = index % 2
index = parent
# uses the psuedo-LRU tree to select
# a victim way from the given set
# returns the victim way as an integer
def getvictimway(self, setnum):
if self.numways == 1:
return 0
tree = self.pLRU[setnum]
index = 0
bottomrow = (self.numways - 1) // 2 #first index on the bottom row of the tree
while index < bottomrow:
if tree[index] == 0:
# Go to the left child
index = index*2 + 1
else: #tree[index] == 1
# Go to the right child
index = index*2 + 2
victim = (index - bottomrow)*2
if tree[index] == 1:
victim += 1
return victim
def __str__(self):
string = ""
for i in range(self.numways):
string += "Way " + str(i) + ": "
for line in self.ways[i]:
string += str(line) + ", "
string += "\n\n"
return string
def __repr__(self):
return self.__str__()
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Simulates a L1 cache.")
parser.add_argument('numlines', type=int, help="The number of lines per way (a power of 2)", metavar="L")
parser.add_argument('numways', type=int, help="The number of ways (a power of 2)", metavar='W')
parser.add_argument('addrlen', type=int, help="Length of the address in bits (a power of 2)", metavar="A")
parser.add_argument('taglen', type=int, help="Length of the tag in bits", metavar="T")
parser.add_argument('-f', "--file", required=True, help="Log file to simulate from")
parser.add_argument('-v', "--verbose", action='store_true', help="verbose/full-trace mode")
args = parser.parse_args()
cache = Cache(args.numlines, args.numways, args.addrlen, args.taglen)
#numtests = -1
extfile = os.path.expanduser(args.file)
with open(extfile, "r") as f:
for ln in f:
ln = ln.strip()
lninfo = ln.split()
if len(lninfo) < 3: #non-address line
if len(lninfo) > 0 and (lninfo[0] == 'BEGIN' or lninfo[0] == 'TRAIN'):
# currently BEGIN and END traces aren't being recorded correctly
# trying TRAIN clears instead
cache.invalidate() # a new test is starting, so 'empty' the cache
cache.clear_pLRU()
#numtests +=1
if args.verbose:
print("New Test")
else:
if lninfo[1] == 'F':
cache.flush()
if args.verbose:
print("F")
elif lninfo[1] == 'I':
cache.invalidate()
if args.verbose:
print("I")
else:
addr = int(lninfo[0], 16)
iswrite = lninfo[1] == 'W' or lninfo[1] == 'A'
result = cache.cacheaccess(addr, iswrite)
if args.verbose:
tag, setnum, offset = cache.splitaddr(addr)
print(hex(addr), hex(tag), hex(setnum), hex(offset), lninfo[2], result)
if not result == lninfo[2]:
print("Result mismatch at address", lninfo[0], ". Wally:", lninfo[2],", Sim:", result) #, "in test", numtests)

View File

@ -4,24 +4,36 @@
--showcommands --showcommands
# Core settings # Core settings
--override cpu/priv_version=1.12
--override cpu/user_version=20191213
# arch
--override cpu/mimpid=0x100
--override refRoot/cpu/tvec_align=64
# clarify
#--override refRoot/cpu/mtvec_sext=F
--override cpu/tval_ii_code=T
#--override cpu/time_undefined=T
#--override cpu/cycle_undefined=T
#--override cpu/instret_undefined=T
#--override cpu/hpmcounter_undefined=T
--override cpu/reset_address=0x80000000
--override cpu/unaligned=F --override cpu/unaligned=F
--override cpu/ignore_non_leaf_DAU=1 --override cpu/ignore_non_leaf_DAU=1
#--override cpu/wfi_is_nop=T --override cpu/wfi_is_nop=T
--override cpu/mimpid=0x100
--override cpu/misa_Extensions_mask=0x0 --override cpu/misa_Extensions_mask=0x0
#--override cpu/updatePTEA=T
#--override cpu/updatePTED=T
--override cpu/Sstc=T
# THIS NEEDS FIXING to 16
--override cpu/PMP_registers=16 --override cpu/PMP_registers=16
--override cpu/PMP_undefined=T --override cpu/PMP_undefined=T
# Wally-specific non-default configuraiton
--override refRoot/cpu/Sstc=T
--override cpu/add_implicit_Extensions=B
--override cpu/bitmanip_version=1.0.0
# Illegal instruction should not contain the bit pattern
# illegal pmp read contained this
# --override cpu/tval_ii_code=F
# PMA Settings # PMA Settings
# 'r': read access allowed # 'r': read access allowed
# 'w': write access allowed # 'w': write access allowed
@ -51,19 +63,11 @@
#-override refRoot/cpu/cv/cover=basic #-override refRoot/cpu/cv/cover=basic
#-override refRoot/cpu/cv/extensions=RV32I #-override refRoot/cpu/cv/extensions=RV32I
# Add Imperas simulator application instruction tracing # Add Imperas simulator application instruction tracing
--override cpu/show_c_prefix=T
--trace --tracechange --traceshowicount --tracemode -tracemem ASX --monitornetschange --traceafter 800000
# Exceptions and pagetables debug
--override cpu/debugflags=6
# Turn on verbose output for Imperas simulator and Model
--verbose --verbose
--override cpu/verbose=1 --trace --tracechange --traceshowicount --tracemode -tracemem ASX --monitornetschange --traceafter 0
--override cpu/debugflags=6 --override cpu/verbose=1
--override cpu/show_c_prefix=T
# Store simulator output to logfile # Store simulator output to logfile
--output imperas.log --output imperas.log

View File

@ -36,7 +36,7 @@ module hazard (
input logic FCvtIntStallD, FPUStallD, input logic FCvtIntStallD, FPUStallD,
input logic DivBusyE, FDivBusyE, input logic DivBusyE, FDivBusyE,
input logic EcallFaultM, BreakpointFaultM, input logic EcallFaultM, BreakpointFaultM,
input logic WFIStallM, input logic wfiM, IntPendingM,
// Stall & flush outputs // Stall & flush outputs
output logic StallF, StallD, StallE, StallM, StallW, output logic StallF, StallD, StallE, StallM, StallW,
output logic FlushD, FlushE, FlushM, FlushW output logic FlushD, FlushE, FlushM, FlushW
@ -45,6 +45,12 @@ module hazard (
logic StallFCause, StallDCause, StallECause, StallMCause, StallWCause; logic StallFCause, StallDCause, StallECause, StallMCause, StallWCause;
logic LatestUnstalledD, LatestUnstalledE, LatestUnstalledM, LatestUnstalledW; logic LatestUnstalledD, LatestUnstalledE, LatestUnstalledM, LatestUnstalledW;
logic FlushDCause, FlushECause, FlushMCause, FlushWCause; logic FlushDCause, FlushECause, FlushMCause, FlushWCause;
logic WFIStallM, WFIInterruptedM;
// WFI logic
assign WFIStallM = wfiM & ~IntPendingM; // WFI waiting for an interrupt or timeout
assign WFIInterruptedM = wfiM & IntPendingM; // WFI detects a pending interrupt. Retire WFI; trap if interrupt is enabled.
// stalls and flushes // stalls and flushes
// loads: stall for one cycle if the subsequent instruction depends on the load // loads: stall for one cycle if the subsequent instruction depends on the load
@ -68,7 +74,7 @@ module hazard (
assign FlushDCause = TrapM | RetM | CSRWriteFenceM | BPWrongE; assign FlushDCause = TrapM | RetM | CSRWriteFenceM | BPWrongE;
assign FlushECause = TrapM | RetM | CSRWriteFenceM |(BPWrongE & ~(DivBusyE | FDivBusyE)); assign FlushECause = TrapM | RetM | CSRWriteFenceM |(BPWrongE & ~(DivBusyE | FDivBusyE));
assign FlushMCause = TrapM | RetM | CSRWriteFenceM; assign FlushMCause = TrapM | RetM | CSRWriteFenceM;
assign FlushWCause = TrapM; assign FlushWCause = TrapM & ~WFIInterruptedM;
// Stall causes // Stall causes
// Most data depenency stalls are identified in the decode stage // Most data depenency stalls are identified in the decode stage

View File

@ -62,7 +62,7 @@ module lsu (
output logic LoadPageFaultM, StoreAmoPageFaultM, // Page fault exceptions output logic LoadPageFaultM, StoreAmoPageFaultM, // Page fault exceptions
output logic LoadMisalignedFaultM, // Load address misaligned fault output logic LoadMisalignedFaultM, // Load address misaligned fault
output logic LoadAccessFaultM, // Load access fault (PMA) output logic LoadAccessFaultM, // Load access fault (PMA)
output logic HPTWInstrAccessFaultM, // HPTW generated access fault during instruction fetch output logic HPTWInstrAccessFaultF, // HPTW generated access fault during instruction fetch
// cpu hazard unit (trap) // cpu hazard unit (trap)
output logic StoreAmoMisalignedFaultM, // Store or AMO address misaligned fault output logic StoreAmoMisalignedFaultM, // Store or AMO address misaligned fault
output logic StoreAmoAccessFaultM, // Store or AMO access fault output logic StoreAmoAccessFaultM, // Store or AMO access fault
@ -159,7 +159,7 @@ module lsu (
.IEUAdrExtM, .PTE, .IHWriteDataM, .PageType, .PreLSURWM, .LSUAtomicM, .IEUAdrExtM, .PTE, .IHWriteDataM, .PageType, .PreLSURWM, .LSUAtomicM,
.IHAdrM, .HPTWStall, .SelHPTW, .IHAdrM, .HPTWStall, .SelHPTW,
.IgnoreRequestTLB, .LSULoadAccessFaultM, .LSUStoreAmoAccessFaultM, .IgnoreRequestTLB, .LSULoadAccessFaultM, .LSUStoreAmoAccessFaultM,
.LoadAccessFaultM, .StoreAmoAccessFaultM, .HPTWInstrAccessFaultM); .LoadAccessFaultM, .StoreAmoAccessFaultM, .HPTWInstrAccessFaultF);
end else begin // No HPTW, so signals are not multiplexed end else begin // No HPTW, so signals are not multiplexed
assign PreLSURWM = MemRWM; assign PreLSURWM = MemRWM;
assign IHAdrM = IEUAdrExtM; assign IHAdrM = IEUAdrExtM;
@ -170,7 +170,7 @@ module lsu (
assign LoadAccessFaultM = LSULoadAccessFaultM; assign LoadAccessFaultM = LSULoadAccessFaultM;
assign StoreAmoAccessFaultM = LSUStoreAmoAccessFaultM; assign StoreAmoAccessFaultM = LSUStoreAmoAccessFaultM;
assign {HPTWStall, SelHPTW, PTE, PageType, DTLBWriteM, ITLBWriteF, IgnoreRequestTLB} = '0; assign {HPTWStall, SelHPTW, PTE, PageType, DTLBWriteM, ITLBWriteF, IgnoreRequestTLB} = '0;
assign HPTWInstrAccessFaultM = '0; assign HPTWInstrAccessFaultF = '0;
end end
// CommittedM indicates the cache, bus, or HPTW are busy with a multiple cycle operation. // CommittedM indicates the cache, bus, or HPTW are busy with a multiple cycle operation.

View File

@ -64,7 +64,7 @@ module hptw (
output logic SelHPTW, output logic SelHPTW,
output logic HPTWStall, output logic HPTWStall,
input logic LSULoadAccessFaultM, LSUStoreAmoAccessFaultM, input logic LSULoadAccessFaultM, LSUStoreAmoAccessFaultM,
output logic LoadAccessFaultM, StoreAmoAccessFaultM, HPTWInstrAccessFaultM output logic LoadAccessFaultM, StoreAmoAccessFaultM, HPTWInstrAccessFaultF
); );
typedef enum logic [3:0] {L0_ADR, L0_RD, typedef enum logic [3:0] {L0_ADR, L0_RD,
@ -98,12 +98,25 @@ module hptw (
logic [1:0] HPTWRW; logic [1:0] HPTWRW;
logic [2:0] HPTWSize; // 32 or 64 bit access logic [2:0] HPTWSize; // 32 or 64 bit access
statetype WalkerState, NextWalkerState, InitialWalkerState; statetype WalkerState, NextWalkerState, InitialWalkerState;
logic HPTWLoadAccessFault, HPTWStoreAmoAccessFault, HPTWInstrAccessFault;
logic HPTWLoadAccessFaultDelay, HPTWStoreAmoAccessFaultDelay, HPTWInstrAccessFaultDelay;
logic HPTWAccessFaultDelay;
logic TakeHPTWFault, TakeHPTWFaultDelay;
// map hptw access faults onto either the original LSU load/store fault or instruction access fault // map hptw access faults onto either the original LSU load/store fault or instruction access fault
assign LSUAccessFaultM = LSULoadAccessFaultM | LSUStoreAmoAccessFaultM; assign LSUAccessFaultM = LSULoadAccessFaultM | LSUStoreAmoAccessFaultM;
assign LoadAccessFaultM = WalkerState == IDLE ? LSULoadAccessFaultM : LSUAccessFaultM & DTLBWalk & MemRWM[1] & ~MemRWM[0]; assign HPTWLoadAccessFault = LSUAccessFaultM & DTLBWalk & MemRWM[1] & ~MemRWM[0];
assign StoreAmoAccessFaultM = WalkerState == IDLE ? LSUStoreAmoAccessFaultM : LSUAccessFaultM & DTLBWalk & MemRWM[0]; assign HPTWStoreAmoAccessFault = LSUAccessFaultM & DTLBWalk & MemRWM[0];
assign HPTWInstrAccessFaultM = WalkerState == IDLE ? 1'b0: LSUAccessFaultM & ~DTLBWalk; assign HPTWInstrAccessFault = LSUAccessFaultM & ~DTLBWalk;
flopr #(4) HPTWAccesFaultReg(clk, reset, {TakeHPTWFault, HPTWLoadAccessFault, HPTWStoreAmoAccessFault, HPTWInstrAccessFault},
{TakeHPTWFaultDelay, HPTWLoadAccessFaultDelay, HPTWStoreAmoAccessFaultDelay, HPTWInstrAccessFaultDelay});
assign TakeHPTWFault = WalkerState != IDLE;
assign LoadAccessFaultM = TakeHPTWFaultDelay ? HPTWLoadAccessFaultDelay : LSULoadAccessFaultM;
assign StoreAmoAccessFaultM = TakeHPTWFaultDelay ? HPTWStoreAmoAccessFaultDelay : LSUStoreAmoAccessFaultM;
assign HPTWInstrAccessFaultF = TakeHPTWFaultDelay ? HPTWInstrAccessFaultDelay : 1'b0;
// Extract bits from CSRs and inputs // Extract bits from CSRs and inputs
assign SvMode = SATP_REGW[`XLEN-1:`XLEN-`SVMODE_BITS]; assign SvMode = SATP_REGW[`XLEN-1:`XLEN-`SVMODE_BITS];
@ -247,22 +260,26 @@ module hptw (
flopenl #(.TYPE(statetype)) WalkerStateReg(clk, reset | FlushW, 1'b1, NextWalkerState, IDLE, WalkerState); flopenl #(.TYPE(statetype)) WalkerStateReg(clk, reset | FlushW, 1'b1, NextWalkerState, IDLE, WalkerState);
always_comb always_comb
case (WalkerState) case (WalkerState)
IDLE: if (TLBMiss & ~DCacheStallM) NextWalkerState = InitialWalkerState; IDLE: if (TLBMiss & ~DCacheStallM & ~HPTWAccessFaultDelay) NextWalkerState = InitialWalkerState;
else NextWalkerState = IDLE; else NextWalkerState = IDLE;
L3_ADR: NextWalkerState = L3_RD; // first access in SV48 L3_ADR: NextWalkerState = L3_RD; // first access in SV48
L3_RD: if (DCacheStallM) NextWalkerState = L3_RD; L3_RD: if (DCacheStallM) NextWalkerState = L3_RD;
else if(LSUAccessFaultM) NextWalkerState = IDLE;
else NextWalkerState = L2_ADR; else NextWalkerState = L2_ADR;
L2_ADR: if (InitialWalkerState == L2_ADR | ValidNonLeafPTE) NextWalkerState = L2_RD; // first access in SV39 L2_ADR: if (InitialWalkerState == L2_ADR | ValidNonLeafPTE) NextWalkerState = L2_RD; // first access in SV39
else NextWalkerState = LEAF; else NextWalkerState = LEAF;
L2_RD: if (DCacheStallM) NextWalkerState = L2_RD; L2_RD: if (DCacheStallM) NextWalkerState = L2_RD;
else if(LSUAccessFaultM) NextWalkerState = IDLE;
else NextWalkerState = L1_ADR; else NextWalkerState = L1_ADR;
L1_ADR: if (InitialWalkerState == L1_ADR | ValidNonLeafPTE) NextWalkerState = L1_RD; // first access in SV32 L1_ADR: if (InitialWalkerState == L1_ADR | ValidNonLeafPTE) NextWalkerState = L1_RD; // first access in SV32
else NextWalkerState = LEAF; else NextWalkerState = LEAF;
L1_RD: if (DCacheStallM) NextWalkerState = L1_RD; L1_RD: if (DCacheStallM) NextWalkerState = L1_RD;
else if(LSUAccessFaultM) NextWalkerState = IDLE;
else NextWalkerState = L0_ADR; else NextWalkerState = L0_ADR;
L0_ADR: if (ValidNonLeafPTE) NextWalkerState = L0_RD; L0_ADR: if (ValidNonLeafPTE) NextWalkerState = L0_RD;
else NextWalkerState = LEAF; else NextWalkerState = LEAF;
L0_RD: if (DCacheStallM) NextWalkerState = L0_RD; L0_RD: if (DCacheStallM) NextWalkerState = L0_RD;
else if(LSUAccessFaultM) NextWalkerState = IDLE;
else NextWalkerState = LEAF; else NextWalkerState = LEAF;
LEAF: if (`SVADU_SUPPORTED & HPTWUpdateDA) NextWalkerState = UPDATE_PTE; LEAF: if (`SVADU_SUPPORTED & HPTWUpdateDA) NextWalkerState = UPDATE_PTE;
else NextWalkerState = IDLE; else NextWalkerState = IDLE;
@ -273,7 +290,8 @@ module hptw (
assign IgnoreRequestTLB = WalkerState == IDLE & TLBMiss; assign IgnoreRequestTLB = WalkerState == IDLE & TLBMiss;
assign SelHPTW = WalkerState != IDLE; assign SelHPTW = WalkerState != IDLE;
assign HPTWStall = (WalkerState != IDLE) | (WalkerState == IDLE & TLBMiss); assign HPTWAccessFaultDelay = HPTWLoadAccessFaultDelay | HPTWStoreAmoAccessFaultDelay | HPTWInstrAccessFaultDelay;
assign HPTWStall = (WalkerState != IDLE) | (WalkerState == IDLE & TLBMiss & ~(HPTWAccessFaultDelay));
assign ITLBMissOrUpdateDAF = ITLBMissF | (`SVADU_SUPPORTED & InstrUpdateDAF); assign ITLBMissOrUpdateDAF = ITLBMissF | (`SVADU_SUPPORTED & InstrUpdateDAF);
assign DTLBMissOrUpdateDAM = DTLBMissM | (`SVADU_SUPPORTED & DataUpdateDAM); assign DTLBMissOrUpdateDAM = DTLBMissM | (`SVADU_SUPPORTED & DataUpdateDAM);

View File

@ -65,7 +65,7 @@ module privileged (
// fault sources // fault sources
input logic InstrAccessFaultF, // instruction access fault input logic InstrAccessFaultF, // instruction access fault
input logic LoadAccessFaultM, StoreAmoAccessFaultM, // load or store access fault input logic LoadAccessFaultM, StoreAmoAccessFaultM, // load or store access fault
input logic HPTWInstrAccessFaultM, // hardware page table access fault while fetching instruction PTE input logic HPTWInstrAccessFaultF, // hardware page table access fault while fetching instruction PTE
input logic InstrPageFaultF, // page faults input logic InstrPageFaultF, // page faults
input logic LoadPageFaultM, StoreAmoPageFaultM, // page faults input logic LoadPageFaultM, StoreAmoPageFaultM, // page faults
input logic InstrMisalignedFaultM, // misaligned instruction fault input logic InstrMisalignedFaultM, // misaligned instruction fault
@ -93,7 +93,7 @@ module privileged (
output logic BigEndianM, // Use big endian in current privilege mode output logic BigEndianM, // Use big endian in current privilege mode
// Fault outputs // Fault outputs
output logic BreakpointFaultM, EcallFaultM, // breakpoint and Ecall traps should retire output logic BreakpointFaultM, EcallFaultM, // breakpoint and Ecall traps should retire
output logic WFIStallM // Stall in Memory stage for WFI until interrupt or timeout output logic wfiM, IntPendingM // Stall in Memory stage for WFI until interrupt pending or timeout
); );
logic [3:0] CauseM; // trap cause logic [3:0] CauseM; // trap cause
@ -110,10 +110,10 @@ module privileged (
logic [11:0] MIP_REGW, MIE_REGW; // interrupt pending and enable bits logic [11:0] MIP_REGW, MIE_REGW; // interrupt pending and enable bits
logic [1:0] NextPrivilegeModeM; // next privilege mode based on trap or return logic [1:0] NextPrivilegeModeM; // next privilege mode based on trap or return
logic DelegateM; // trap should be delegated logic DelegateM; // trap should be delegated
logic wfiM; // wait for interrupt instruction
logic IntPendingM; // interrupt is pending, even if not enabled. ends wfi
logic InterruptM; // interrupt occuring logic InterruptM; // interrupt occuring
logic ExceptionM; // Memory stage instruction caused a fault logic ExceptionM; // Memory stage instruction caused a fault
logic HPTWInstrAccessFaultM; // Hardware page table access fault while fetching instruction PTE
// track the current privilege level // track the current privilege level
privmode privmode(.clk, .reset, .StallW, .TrapM, .mretM, .sretM, .DelegateM, privmode privmode(.clk, .reset, .StallW, .TrapM, .mretM, .sretM, .DelegateM,
@ -144,8 +144,8 @@ module privileged (
// pipeline early-arriving trap sources // pipeline early-arriving trap sources
privpiperegs ppr(.clk, .reset, .StallD, .StallE, .StallM, .FlushD, .FlushE, .FlushM, privpiperegs ppr(.clk, .reset, .StallD, .StallE, .StallM, .FlushD, .FlushE, .FlushM,
.InstrPageFaultF, .InstrAccessFaultF, .IllegalIEUFPUInstrD, .InstrPageFaultF, .InstrAccessFaultF, .HPTWInstrAccessFaultF, .IllegalIEUFPUInstrD,
.InstrPageFaultM, .InstrAccessFaultM, .IllegalIEUFPUInstrM); .InstrPageFaultM, .InstrAccessFaultM, .HPTWInstrAccessFaultM, .IllegalIEUFPUInstrM);
// trap logic // trap logic
trap trap(.reset, trap trap(.reset,
@ -156,7 +156,7 @@ module privileged (
.mretM, .sretM, .PrivilegeModeW, .mretM, .sretM, .PrivilegeModeW,
.MIP_REGW, .MIE_REGW, .MIDELEG_REGW, .MEDELEG_REGW, .STATUS_MIE, .STATUS_SIE, .MIP_REGW, .MIE_REGW, .MIDELEG_REGW, .MEDELEG_REGW, .STATUS_MIE, .STATUS_SIE,
.InstrValidM, .CommittedM, .CommittedF, .InstrValidM, .CommittedM, .CommittedF,
.TrapM, .RetM, .wfiM, .InterruptM, .ExceptionM, .IntPendingM, .DelegateM, .WFIStallM, .CauseM); .TrapM, .RetM, .wfiM, .InterruptM, .ExceptionM, .IntPendingM, .DelegateM, .CauseM);
endmodule endmodule

View File

@ -33,24 +33,26 @@ module privpiperegs (
input logic StallD, StallE, StallM, input logic StallD, StallE, StallM,
input logic FlushD, FlushE, FlushM, input logic FlushD, FlushE, FlushM,
input logic InstrPageFaultF, InstrAccessFaultF, // instruction faults input logic InstrPageFaultF, InstrAccessFaultF, // instruction faults
input logic HPTWInstrAccessFaultF, // hptw fault during instruction page fetch
input logic IllegalIEUFPUInstrD, // illegal IEU instruction decoded input logic IllegalIEUFPUInstrD, // illegal IEU instruction decoded
output logic InstrPageFaultM, InstrAccessFaultM, // delayed instruction faults output logic InstrPageFaultM, InstrAccessFaultM, // delayed instruction faults
output logic IllegalIEUFPUInstrM // delayed illegal IEU instruction output logic IllegalIEUFPUInstrM, // delayed illegal IEU instruction
output logic HPTWInstrAccessFaultM // hptw fault during instruction page fetch
); );
// Delayed fault signals // Delayed fault signals
logic InstrPageFaultD, InstrAccessFaultD; logic InstrPageFaultD, InstrAccessFaultD, HPTWInstrAccessFaultD;
logic InstrPageFaultE, InstrAccessFaultE; logic InstrPageFaultE, InstrAccessFaultE, HPTWInstrAccessFaultE;
logic IllegalIEUFPUInstrE; logic IllegalIEUFPUInstrE;
// pipeline fault signals // pipeline fault signals
flopenrc #(2) faultregD(clk, reset, FlushD, ~StallD, flopenrc #(3) faultregD(clk, reset, FlushD, ~StallD,
{InstrPageFaultF, InstrAccessFaultF}, {InstrPageFaultF, InstrAccessFaultF, HPTWInstrAccessFaultF},
{InstrPageFaultD, InstrAccessFaultD}); {InstrPageFaultD, InstrAccessFaultD, HPTWInstrAccessFaultD});
flopenrc #(3) faultregE(clk, reset, FlushE, ~StallE, flopenrc #(4) faultregE(clk, reset, FlushE, ~StallE,
{IllegalIEUFPUInstrD, InstrPageFaultD, InstrAccessFaultD}, {IllegalIEUFPUInstrD, InstrPageFaultD, InstrAccessFaultD, HPTWInstrAccessFaultD},
{IllegalIEUFPUInstrE, InstrPageFaultE, InstrAccessFaultE}); {IllegalIEUFPUInstrE, InstrPageFaultE, InstrAccessFaultE, HPTWInstrAccessFaultE});
flopenrc #(3) faultregM(clk, reset, FlushM, ~StallM, flopenrc #(4) faultregM(clk, reset, FlushM, ~StallM,
{IllegalIEUFPUInstrE, InstrPageFaultE, InstrAccessFaultE}, {IllegalIEUFPUInstrE, InstrPageFaultE, InstrAccessFaultE, HPTWInstrAccessFaultE},
{IllegalIEUFPUInstrM, InstrPageFaultM, InstrAccessFaultM}); {IllegalIEUFPUInstrM, InstrPageFaultM, InstrAccessFaultM, HPTWInstrAccessFaultM});
endmodule endmodule

View File

@ -48,7 +48,6 @@ module trap (
output logic ExceptionM, // exception is occurring output logic ExceptionM, // exception is occurring
output logic IntPendingM, // Interrupt is pending, might occur if enabled output logic IntPendingM, // Interrupt is pending, might occur if enabled
output logic DelegateM, // Delegate trap to supervisor handler output logic DelegateM, // Delegate trap to supervisor handler
output logic WFIStallM, // Stall due to WFI instruction
output logic [3:0] CauseM // trap cause output logic [3:0] CauseM // trap cause
); );
@ -74,7 +73,6 @@ module trap (
assign InterruptM = (|ValidIntsM) & InstrValidM; // suppress interrupt if the memory system has partially processed a request. assign InterruptM = (|ValidIntsM) & InstrValidM; // suppress interrupt if the memory system has partially processed a request.
assign DelegateM = `S_SUPPORTED & (InterruptM ? MIDELEG_REGW[CauseM] : MEDELEG_REGW[CauseM]) & assign DelegateM = `S_SUPPORTED & (InterruptM ? MIDELEG_REGW[CauseM] : MEDELEG_REGW[CauseM]) &
(PrivilegeModeW == `U_MODE | PrivilegeModeW == `S_MODE); (PrivilegeModeW == `U_MODE | PrivilegeModeW == `S_MODE);
assign WFIStallM = wfiM & ~IntPendingM;
/////////////////////////////////////////// ///////////////////////////////////////////
// Trigger Traps and RET // Trigger Traps and RET

View File

@ -106,7 +106,7 @@ module wallypipelinedcore (
logic [1:0] PrivilegeModeW; logic [1:0] PrivilegeModeW;
logic [`XLEN-1:0] PTE; logic [`XLEN-1:0] PTE;
logic [1:0] PageType; logic [1:0] PageType;
logic sfencevmaM, WFIStallM; logic sfencevmaM;
logic SelHPTW; logic SelHPTW;
// PMA checker signals // PMA checker signals
@ -146,7 +146,7 @@ module wallypipelinedcore (
logic RASPredPCWrongM; logic RASPredPCWrongM;
logic IClassWrongM; logic IClassWrongM;
logic [3:0] InstrClassM; logic [3:0] InstrClassM;
logic InstrAccessFaultF, HPTWInstrAccessFaultM; logic InstrAccessFaultF, HPTWInstrAccessFaultF;
logic [2:0] LSUHSIZE; logic [2:0] LSUHSIZE;
logic [2:0] LSUHBURST; logic [2:0] LSUHBURST;
logic [1:0] LSUHTRANS; logic [1:0] LSUHTRANS;
@ -162,7 +162,8 @@ module wallypipelinedcore (
logic CommittedF; logic CommittedF;
logic BranchD, BranchE, JumpD, JumpE; logic BranchD, BranchE, JumpD, JumpE;
logic DCacheStallM, ICacheStallF; logic DCacheStallM, ICacheStallF;
logic wfiM, IntPendingM;
// instruction fetch unit: PC, branch prediction, instruction cache // instruction fetch unit: PC, branch prediction, instruction cache
ifu ifu(.clk, .reset, ifu ifu(.clk, .reset,
.StallF, .StallD, .StallE, .StallM, .StallW, .FlushD, .FlushE, .FlushM, .FlushW, .StallF, .StallD, .StallE, .StallM, .StallW, .FlushD, .FlushE, .FlushM, .FlushW,
@ -236,7 +237,7 @@ module wallypipelinedcore (
.StoreAmoPageFaultM, // connects to privilege .StoreAmoPageFaultM, // connects to privilege
.LoadMisalignedFaultM, // connects to privilege .LoadMisalignedFaultM, // connects to privilege
.LoadAccessFaultM, // connects to privilege .LoadAccessFaultM, // connects to privilege
.HPTWInstrAccessFaultM, // connects to privilege .HPTWInstrAccessFaultF, // connects to privilege
.StoreAmoMisalignedFaultM, // connects to privilege .StoreAmoMisalignedFaultM, // connects to privilege
.StoreAmoAccessFaultM, // connects to privilege .StoreAmoAccessFaultM, // connects to privilege
.InstrUpdateDAF, .InstrUpdateDAF,
@ -265,7 +266,7 @@ module wallypipelinedcore (
.FCvtIntStallD, .FPUStallD, .FCvtIntStallD, .FPUStallD,
.DivBusyE, .FDivBusyE, .DivBusyE, .FDivBusyE,
.EcallFaultM, .BreakpointFaultM, .EcallFaultM, .BreakpointFaultM,
.WFIStallM, .wfiM, .IntPendingM,
// Stall & flush outputs // Stall & flush outputs
.StallF, .StallD, .StallE, .StallM, .StallW, .StallF, .StallD, .StallE, .StallM, .StallW,
.FlushD, .FlushE, .FlushM, .FlushW); .FlushD, .FlushE, .FlushM, .FlushW);
@ -288,17 +289,18 @@ module wallypipelinedcore (
.LoadMisalignedFaultM, .StoreAmoMisalignedFaultM, .LoadMisalignedFaultM, .StoreAmoMisalignedFaultM,
.MTimerInt, .MExtInt, .SExtInt, .MSwInt, .MTimerInt, .MExtInt, .SExtInt, .MSwInt,
.MTIME_CLINT, .IEUAdrM, .SetFflagsM, .MTIME_CLINT, .IEUAdrM, .SetFflagsM,
.InstrAccessFaultF, .HPTWInstrAccessFaultM, .LoadAccessFaultM, .StoreAmoAccessFaultM, .SelHPTW, .InstrAccessFaultF, .HPTWInstrAccessFaultF, .LoadAccessFaultM, .StoreAmoAccessFaultM, .SelHPTW,
.PrivilegeModeW, .SATP_REGW, .PrivilegeModeW, .SATP_REGW,
.STATUS_MXR, .STATUS_SUM, .STATUS_MPRV, .STATUS_MPP, .STATUS_FS, .STATUS_MXR, .STATUS_SUM, .STATUS_MPRV, .STATUS_MPP, .STATUS_FS,
.PMPCFG_ARRAY_REGW, .PMPADDR_ARRAY_REGW, .PMPCFG_ARRAY_REGW, .PMPADDR_ARRAY_REGW,
.FRM_REGW,.BreakpointFaultM, .EcallFaultM, .WFIStallM, .BigEndianM); .FRM_REGW,.BreakpointFaultM, .EcallFaultM, .wfiM, .IntPendingM, .BigEndianM);
end else begin end else begin
assign CSRReadValW = 0; assign CSRReadValW = 0;
assign UnalignedPCNextF = PC2NextF; assign UnalignedPCNextF = PC2NextF;
assign RetM = 0; assign RetM = 0;
assign TrapM = 0; assign TrapM = 0;
assign WFIStallM = 0; assign wfiM = 0;
assign IntPendingM = 0;
assign sfencevmaM = 0; assign sfencevmaM = 0;
assign BigEndianM = 0; assign BigEndianM = 0;
end end

View File

@ -413,10 +413,11 @@ module testbench;
end end
end end
always @(dut.core.MTimerInt) void'(rvvi.net_push("MTimerInterrupt", dut.core.MTimerInt)); always @(dut.core.MTimerInt) void'(rvvi.net_push("MTimerInterrupt", dut.core.MTimerInt));
always @(dut.core.MExtInt) void'(rvvi.net_push("MExternalInterrupt", dut.core.MExtInt)); always @(dut.core.MExtInt) void'(rvvi.net_push("MExternalInterrupt", dut.core.MExtInt));
always @(dut.core.SExtInt) void'(rvvi.net_push("SExternalInterrupt", dut.core.SExtInt)); always @(dut.core.SExtInt) void'(rvvi.net_push("SExternalInterrupt", dut.core.SExtInt));
always @(dut.core.MSwInt) void'(rvvi.net_push("MSWInterrupt", dut.core.MSwInt)); always @(dut.core.MSwInt) void'(rvvi.net_push("MSWInterrupt", dut.core.MSwInt));
always @(dut.core.priv.priv.csr.csrs.csrs.STimerInt) void'(rvvi.net_push("STimerInterrupt", dut.core.priv.priv.csr.csrs.csrs.STimerInt));
final begin final begin
void'(rvviRefShutdown()); void'(rvviRefShutdown());

View File

@ -480,7 +480,7 @@ logic [3:0] dummy;
assign EndSample = DCacheFlushStart & ~DCacheFlushDone; assign EndSample = DCacheFlushStart & ~DCacheFlushDone;
flop #(1) BeginReg(clk, StartSampleFirst, BeginDelayed); flop #(1) BeginReg(clk, StartSampleFirst, BeginDelayed);
assign Begin = StartSampleFirst & ~ BeginDelayed; assign Begin = StartSampleFirst & ~BeginDelayed;
end end
@ -555,12 +555,16 @@ logic [3:0] dummy;
end end
if (`ICACHE_SUPPORTED && `I_CACHE_ADDR_LOGGER) begin if (`ICACHE_SUPPORTED && `I_CACHE_ADDR_LOGGER) begin : ICacheLogger
int file; int file;
string LogFile; string LogFile;
logic resetD, resetEdge; logic resetD, resetEdge;
logic Enable; logic Enable;
assign Enable = ~dut.core.StallD & ~dut.core.FlushD & dut.core.ifu.bus.icache.CacheRWF[1] & ~reset; // assign Enable = ~dut.core.StallD & ~dut.core.FlushD & dut.core.ifu.bus.icache.CacheRWF[1] & ~reset;
// this version of Enable allows for accurate eviction logging.
// Likely needs further improvement.
assign Enable = dut.core.ifu.bus.icache.icache.cachefsm.LRUWriteEn & ~reset;
flop #(1) ResetDReg(clk, reset, resetD); flop #(1) ResetDReg(clk, reset, resetD);
assign resetEdge = ~reset & resetD; assign resetEdge = ~reset & resetD;
initial begin initial begin
@ -568,50 +572,64 @@ end
file = $fopen(LogFile, "w"); file = $fopen(LogFile, "w");
$fwrite(file, "BEGIN %s\n", memfilename); $fwrite(file, "BEGIN %s\n", memfilename);
end end
string HitMissString; string AccessTypeString, HitMissString;
assign HitMissString = dut.core.ifu.bus.icache.icache.CacheHit ? "H" : "M"; assign HitMissString = dut.core.ifu.bus.icache.icache.CacheHit ? "H" :
dut.core.ifu.bus.icache.icache.vict.cacheLRU.AllValid ? "E" : "M";
assign AccessTypeString = dut.core.ifu.InvalidateICacheM ? "I" : "R";
always @(posedge clk) begin always @(posedge clk) begin
if(resetEdge) $fwrite(file, "TRAIN\n"); if(resetEdge) $fwrite(file, "TRAIN\n");
if(Begin) $fwrite(file, "BEGIN %s\n", memfilename); if(Begin) $fwrite(file, "BEGIN %s\n", memfilename);
if(Enable) begin // only log i cache reads if(Enable) begin // only log i cache reads
$fwrite(file, "%h R %s\n", dut.core.ifu.PCPF, HitMissString); $fwrite(file, "%h %s %s\n", dut.core.ifu.PCPF, AccessTypeString, HitMissString);
end end
if(EndSample) $fwrite(file, "END %s\n", memfilename); if(EndSample) $fwrite(file, "END %s\n", memfilename);
end end
end end
if (`DCACHE_SUPPORTED && `D_CACHE_ADDR_LOGGER) begin
if (`DCACHE_SUPPORTED && `D_CACHE_ADDR_LOGGER) begin : DCacheLogger
int file; int file;
string LogFile; string LogFile;
logic resetD, resetEdge; logic resetD, resetEdge;
string HitMissString; logic Enabled;
string AccessTypeString, HitMissString;
flop #(1) ResetDReg(clk, reset, resetD); flop #(1) ResetDReg(clk, reset, resetD);
assign resetEdge = ~reset & resetD; assign resetEdge = ~reset & resetD;
assign HitMissString = dut.core.lsu.bus.dcache.dcache.CacheHit ? "H" : "M"; assign HitMissString = dut.core.lsu.bus.dcache.dcache.CacheHit ? "H" :
(!dut.core.lsu.bus.dcache.dcache.vict.cacheLRU.AllValid) ? "M" :
dut.core.lsu.bus.dcache.dcache.LineDirty ? "D" : "E";
assign AccessTypeString = dut.core.lsu.bus.dcache.FlushDCache ? "F" :
dut.core.lsu.bus.dcache.CacheAtomicM[1] ? "A" :
dut.core.lsu.bus.dcache.CacheRWM == 2'b10 ? "R" :
dut.core.lsu.bus.dcache.CacheRWM == 2'b01 ? "W" :
"NULL";
// assign Enabled = (dut.core.lsu.bus.dcache.dcache.cachefsm.CurrState == 0) &
// ~dut.core.lsu.bus.dcache.dcache.cachefsm.FlushStage &
// (AccessTypeString != "NULL");
// This version of enable allows for accurate eviction logging.
// Likely needs further improvement.
assign Enabled = dut.core.lsu.bus.dcache.dcache.cachefsm.LRUWriteEn &
~dut.core.lsu.bus.dcache.dcache.cachefsm.FlushStage &
(AccessTypeString != "NULL");
initial begin initial begin
LogFile = $psprintf("DCache.log"); LogFile = $psprintf("DCache.log");
file = $fopen(LogFile, "w"); file = $fopen(LogFile, "w");
$fwrite(file, "BEGIN %s\n", memfilename); $fwrite(file, "BEGIN %s\n", memfilename);
end end
always @(posedge clk) begin always @(posedge clk) begin
if(resetEdge) $fwrite(file, "TRAIN\n"); if(resetEdge) $fwrite(file, "TRAIN\n");
if(Begin) $fwrite(file, "BEGIN %s\n", memfilename); if(Begin) $fwrite(file, "BEGIN %s\n", memfilename);
if(~dut.core.StallW & ~dut.core.FlushW & dut.core.InstrValidM) begin if(Enabled) begin
if(dut.core.lsu.bus.dcache.CacheRWM == 2'b10) begin $fwrite(file, "%h %s %s\n", dut.core.lsu.PAdrM, AccessTypeString, HitMissString);
$fwrite(file, "%h R %s\n", dut.core.lsu.PAdrM, HitMissString);
end else if (dut.core.lsu.bus.dcache.CacheRWM == 2'b01) begin
$fwrite(file, "%h W %s\n", dut.core.lsu.PAdrM, HitMissString);
end else if (dut.core.lsu.bus.dcache.CacheAtomicM[1] == 1'b1) begin // *** This may change
$fwrite(file, "%h A %s\n", dut.core.lsu.PAdrM, HitMissString);
end else if (dut.core.lsu.bus.dcache.FlushDCache) begin
$fwrite(file, "%h F %s\n", dut.core.lsu.PAdrM, HitMissString);
end
end end
if(EndSample) $fwrite(file, "END %s\n", memfilename); if(EndSample) $fwrite(file, "END %s\n", memfilename);
end end
end end
if (`BPRED_SUPPORTED) begin if (`BPRED_SUPPORTED) begin : BranchLogger
if (`BPRED_LOGGER) begin if (`BPRED_LOGGER) begin
string direction; string direction;
int file; int file;

View File

@ -198,10 +198,12 @@ module testbench;
end end
always @(dut.core.MTimerInt) void'(rvvi.net_push("MTimerInterrupt", dut.core.MTimerInt)); always @(dut.core.MTimerInt) void'(rvvi.net_push("MTimerInterrupt", dut.core.MTimerInt));
always @(dut.core.MExtInt) void'(rvvi.net_push("MExternalInterrupt", dut.core.MExtInt)); always @(dut.core.MExtInt) void'(rvvi.net_push("MExternalInterrupt", dut.core.MExtInt));
always @(dut.core.SExtInt) void'(rvvi.net_push("SExternalInterrupt", dut.core.SExtInt)); always @(dut.core.SExtInt) void'(rvvi.net_push("SExternalInterrupt", dut.core.SExtInt));
always @(dut.core.MSwInt) void'(rvvi.net_push("MSWInterrupt", dut.core.MSwInt)); always @(dut.core.MSwInt) void'(rvvi.net_push("MSWInterrupt", dut.core.MSwInt));
always @(dut.core.priv.priv.csr.csrs.csrs.STimerInt) void'(rvvi.net_push("STimerInterrupt", dut.core.priv.priv.csr.csrs.csrs.STimerInt));
final begin final begin
void'(rvviRefShutdown()); void'(rvviRefShutdown());

View File

@ -0,0 +1,89 @@
#!/usr/bin/env python3
###########################################
## CacheSimTest.py
##
## Written: lserafini@hmc.edu
## Created: 4 April 2023
## Modified: 5 April 2023
##
## Purpose: Confirm that the cache simulator behaves as expected.
##
## 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.
################################################################################################
import sys
import os
sys.path.append(os.path.expanduser("~/cvw/bin"))
import CacheSim as cs
if __name__ == "__main__":
cache = cs.Cache(16, 4, 16, 8)
# 0xABCD -> tag: AB, set: C, offset: D
#address split checking
assert (cache.splitaddr(0x1234) == (0x12,0x3,0x4))
assert (cache.splitaddr(0x2638) == (0x26,0x3,0x8))
assert (cache.splitaddr(0xA3E6) == (0xA3,0xE,0x6))
#insert way 0 set C tag AB
assert (cache.cacheaccess(0xABCD) == 'M')
assert (cache.ways[0][0xC].tag == 0xAB)
assert (cache.cacheaccess(0xABCD) == 'H')
assert (cache.pLRU[0xC] == [1,1,0])
#make way 0 set C dirty
assert (cache.cacheaccess(0xABCD, True) == 'H')
#insert way 1 set C tag AC
assert (cache.cacheaccess(0xACCD) == 'M')
assert (cache.ways[1][0xC].tag == 0xAC)
assert (cache.pLRU[0xC] == [1,0,0])
#insert way 2 set C tag AD
assert (cache.cacheaccess(0xADCD) == 'M')
assert (cache.ways[2][0xC].tag == 0xAD)
assert (cache.pLRU[0xC] == [0,0,1])
#insert way 3 set C tag AE
assert (cache.cacheaccess(0xAECD) == 'M')
assert (cache.ways[3][0xC].tag == 0xAE)
assert (cache.pLRU[0xC] == [0,0,0])
#misc hit and pLRU checking
assert (cache.cacheaccess(0xABCD) == 'H')
assert (cache.pLRU[0xC] == [1,1,0])
assert (cache.cacheaccess(0xADCD) == 'H')
assert (cache.pLRU[0xC] == [0,1,1])
#evict way 1, now set C has tag AF
assert (cache.cacheaccess(0xAFCD) == 'E')
assert (cache.ways[1][0xC].tag == 0xAF)
assert (cache.pLRU[0xC] == [1,0,1])
#evict way 3, now set C has tag AC
assert (cache.cacheaccess(0xACCD) == 'E')
assert (cache.ways[3][0xC].tag == 0xAC)
assert (cache.pLRU[0xC] == [0,0,0])
#evict way 0, now set C has tag EA
#this line was dirty, so there was a wb
assert (cache.cacheaccess(0xEAC2) == 'D')
assert (cache.ways[0][0xC].tag == 0xEA)
assert (cache.pLRU[0xC] == [1,1,0])