Merge pull request #46 from CTSRD-CHERI/CHERI-benchmarks
Cheri benchmarks
This commit is contained in:
3
.gitmodules
vendored
3
.gitmodules
vendored
@@ -16,3 +16,6 @@
|
||||
[submodule "libs/WindCoreInterface"]
|
||||
path = libs/WindCoreInterface
|
||||
url = https://github.com/CTSRD-CHERI/WindCoreInterface.git
|
||||
[submodule "Tests/benchmarks"]
|
||||
path = Tests/benchmarks
|
||||
url = https://github.com/CTSRD-CHERI/toooba-sim-benchmarks.git
|
||||
|
||||
385
Tests/Run_benchmarks.py
Executable file
385
Tests/Run_benchmarks.py
Executable file
@@ -0,0 +1,385 @@
|
||||
#!/usr/bin/python3
|
||||
|
||||
# Copyright (c) 2018-2019 Bluespec, Inc.
|
||||
# See LICENSE for license details
|
||||
|
||||
usage_line = (
|
||||
" Usage:\n"
|
||||
" $ <this_prog> <simulation_executable> <repo_dir> <logs_dir> <opt verbosity> <opt parallelism> <opt timeout_secs>\n"
|
||||
"\n"
|
||||
" Runs the RISC-V <simulation_executable>\n"
|
||||
" on ISA tests: ELF files taken from <repo-dir>/isa and its sub-directories.\n"
|
||||
"\n"
|
||||
" For each ELF file FOO, saves simulation output in <logs_dir>/FOO.log. \n"
|
||||
"\n"
|
||||
" If <opt verbosity> is given, it must be one of the following:\n"
|
||||
" v1: Print instruction trace during simulation\n"
|
||||
" v2: Print pipeline stage state during simulation\n"
|
||||
"\n"
|
||||
" If <opt parallelism> is given, it must be an integer\n"
|
||||
" Specifies the number of parallel processes used\n"
|
||||
" (creates temporary separate working directories worker_0, worker_1, ...)\n"
|
||||
" By default uses the number of CPUs listed in /proc/cpuinfo - 4.\n"
|
||||
" In any case, limits it to 8.\n"
|
||||
"\n"
|
||||
" If <opt timeout_secs> is given, it must be an integer and must follow an explicit <opt parallelism>\n"
|
||||
" Specifies the number of seconds to wait for each command run.\n"
|
||||
" Defaults to 60s\n."
|
||||
"\n"
|
||||
" Example:\n"
|
||||
" $ <this_prog> .exe_HW_sim ~somebody/GitHub/Toooba ./Logs v1 4\n"
|
||||
" will run the verilator simulation executable on the following RISC-V ISA tests:\n"
|
||||
" ~somebody/GitHub/Tests/benchmarks/*.bin\n"
|
||||
" and will leave a transcript of each test's simulation output in files like\n"
|
||||
" ./Logs/rv32ui-p-add.log\n"
|
||||
" Each log will contain an instruction trace (because of the 'v1' arg).\n"
|
||||
" It will use 4 processes in parallel to run the regressions.\n"
|
||||
" (creating temporary working directories worker_0, ..., worker_4)\n"
|
||||
)
|
||||
|
||||
import sys
|
||||
import os
|
||||
import stat
|
||||
import subprocess
|
||||
|
||||
import multiprocessing
|
||||
|
||||
# ================================================================
|
||||
# DEBUGGING ONLY: This exclude list allows skipping some specific test
|
||||
|
||||
exclude_list = []
|
||||
|
||||
n_workers_max = 8
|
||||
|
||||
timeout = 6000
|
||||
|
||||
def print_hello ():
|
||||
print ("hello")
|
||||
# ================================================================
|
||||
|
||||
def main (argv = None):
|
||||
print ("Use flag --help or --h for a help message")
|
||||
if ((len (argv) <= 1) or
|
||||
(argv [1] == '-h') or (argv [1] == '--help') or
|
||||
(len (argv) < 4)):
|
||||
|
||||
sys.stdout.write (usage_line)
|
||||
sys.stdout.write ("\n")
|
||||
return 0
|
||||
|
||||
# Simulation executable
|
||||
if not (os.path.exists (argv [1])):
|
||||
sys.stderr.write ("ERROR: The given simulation path does not seem to exist?\n")
|
||||
sys.stderr.write (" Simulation path: " + sim_path + "\n")
|
||||
sys.exit (1)
|
||||
args_dict = {'sim_path': os.path.abspath (os.path.normpath (argv [1]))}
|
||||
|
||||
# Repo in which to find ELFs and elf_to_hex executable
|
||||
if (not os.path.exists (argv [2])):
|
||||
sys.stderr.write ("ERROR: repo directory ({0}) does not exist?\n".format (argv [2]))
|
||||
sys.stdout.write ("\n")
|
||||
sys.stdout.write (usage_line)
|
||||
sys.stdout.write ("\n")
|
||||
return 1
|
||||
repo = os.path.abspath (os.path.normpath (argv [2]))
|
||||
|
||||
elfs_path = os.path.join (repo, "Tests", "benchmarks")
|
||||
if (not os.path.exists (elfs_path)):
|
||||
sys.stderr.write ("ERROR: BINs directory ({0}) does not exist?\n".format (elfs_path))
|
||||
sys.stdout.write ("\n")
|
||||
sys.stdout.write (usage_line)
|
||||
sys.stdout.write ("\n")
|
||||
return 1
|
||||
args_dict ['elfs_path'] = elfs_path
|
||||
|
||||
# Logs directory
|
||||
logs_path = os.path.abspath (os.path.normpath (argv [3]))
|
||||
if not (os.path.exists (logs_path) and os.path.isdir (logs_path)):
|
||||
print ("Creating dir: " + logs_path)
|
||||
os.mkdir (logs_path)
|
||||
args_dict ['logs_path'] = logs_path
|
||||
|
||||
# Optional verbosity
|
||||
verbosity = 0
|
||||
j = 4
|
||||
if len (argv) >= 5:
|
||||
if argv [4] == "v1":
|
||||
verbosity = 1
|
||||
j = 5
|
||||
elif argv [4] == "v2":
|
||||
verbosity = 2
|
||||
j = 5
|
||||
args_dict ['verbosity'] = verbosity
|
||||
|
||||
# Optional parallelism; limit it to 8
|
||||
if len (argv [j:]) != 0 and isdecimal (argv [j]):
|
||||
n_workers = int (argv [j])
|
||||
j = 6
|
||||
else:
|
||||
n_workers = multiprocessing.cpu_count () - 4
|
||||
n_workers = max(min (n_workers_max, n_workers), 1)
|
||||
sys.stdout.write ("Using {0} worker processes\n".format (n_workers))
|
||||
|
||||
global timeout
|
||||
if len(argv[j:]) != 0 and isdecimal (argv[j]):
|
||||
timeout = int(argv[j])
|
||||
j = 7
|
||||
sys.stdout.write (f"Using {timeout}s timeout\n")
|
||||
|
||||
# End of command-line arg processing
|
||||
# ================================================================
|
||||
|
||||
# elf_to_hex executable
|
||||
elf_to_hex_exe = os.path.join (repo, "Tests", "elf_to_hex", "elf_to_hex")
|
||||
if (not os.path.exists (elf_to_hex_exe)):
|
||||
sys.stderr.write ("ERROR: elf_to_hex executable does not exist?\n")
|
||||
sys.stderr.write (" at {0}\n".format (elf_to_hex_exe))
|
||||
sys.stdout.write ("\n")
|
||||
sys.stdout.write (usage_line)
|
||||
sys.stdout.write ("\n")
|
||||
return 1
|
||||
args_dict ['elf_to_hex_exe'] = elf_to_hex_exe
|
||||
|
||||
sys.stdout.write ("Parameters:\n")
|
||||
for key in iter (args_dict):
|
||||
sys.stdout.write (" {0:<16}: {1}\n".format (key, args_dict [key]))
|
||||
|
||||
def fn_filter_regular_file (level, filename):
|
||||
(dirname, basename) = os.path.split (filename)
|
||||
|
||||
# TEMPORARY FILTER WHILE DEBUGGING:
|
||||
if basename in exclude_list:
|
||||
sys.stdout.write ("WARNING: TEMPORARY FILTER IN EFFECT; REMOVE AFTER DEBUGGING\n")
|
||||
sys.stdout.write (" This test is in exclude_list: {0}\n".format (basename))
|
||||
return False
|
||||
|
||||
# Ignore filename if it is not a "*.bin"
|
||||
if basename.find (".bin") != -1:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def fn_filter_dir (level, filename):
|
||||
return True
|
||||
|
||||
# Traverse the elfs_path and collect filenames of relevant isa tests
|
||||
filenames = traverse (fn_filter_dir, fn_filter_regular_file, 0, elfs_path)
|
||||
n_tests = len (filenames)
|
||||
sys.stdout.write ("{0} relevant benchmarks found under {1}\n".format (n_tests, elfs_path))
|
||||
if n_tests == 0:
|
||||
return 0
|
||||
args_dict ['filenames'] = filenames
|
||||
args_dict ['n_tests'] = n_tests
|
||||
|
||||
# Create a shared counter to index into the list of filenames
|
||||
index = multiprocessing.Value ('L', 0) # Unsigned long (4 bytes)
|
||||
args_dict ['index'] = index
|
||||
|
||||
# Create a shared array for each worker's (n_executed, n_passed) results
|
||||
results = multiprocessing.Array ('L', [ 0 for j in range (2 * n_workers) ])
|
||||
args_dict ['results'] = results
|
||||
|
||||
# Create a TAP file to output individual test results in TAP format
|
||||
tap_out = open("../isa_test_report.tap", "w")
|
||||
tap_out.write("1.." + str(n_tests) + "\n")
|
||||
tap_out.close()
|
||||
|
||||
# Create n workers
|
||||
sys.stdout.write ("Creating {0} workers (sub-processes)\n".format (n_workers))
|
||||
workers = [multiprocessing.Process (target = do_worker,
|
||||
#args = (w, args_dict, tap_out))
|
||||
args = (w, args_dict))
|
||||
for w in range (n_workers)]
|
||||
|
||||
# Start the workers
|
||||
for worker in workers: worker.start ()
|
||||
|
||||
# Wait for all workers to finish
|
||||
for worker in workers: worker.join ()
|
||||
|
||||
# Collect all results
|
||||
num_executed = 0
|
||||
num_passed = 0
|
||||
with results.get_lock ():
|
||||
for w in range (n_workers):
|
||||
n_e = results [2 * w]
|
||||
n_p = results [2 * w + 1]
|
||||
sys.stdout.write ("Worker {0} executed {1} tests, of which {2} passed\n"
|
||||
.format (w, n_e, n_p))
|
||||
num_executed = num_executed + n_e
|
||||
num_passed = num_passed + n_p
|
||||
|
||||
# Write final statistics
|
||||
sys.stdout.write ("Total benchmarks: {0} tests\n".format (n_tests))
|
||||
sys.stdout.write ("Executed: {0} tests\n".format (num_executed))
|
||||
sys.stdout.write ("PASS: {0} tests\n".format (num_passed))
|
||||
sys.stdout.write ("FAIL: {0} tests\n".format (num_executed - num_passed))
|
||||
return 0
|
||||
|
||||
# ================================================================
|
||||
# Recursively traverse the dir tree below path and collect filenames
|
||||
# that pass the given filter functions
|
||||
|
||||
def traverse (fn_filter_dir, fn_filter_regular_file, level, path):
|
||||
st = os.stat (path)
|
||||
is_dir = stat.S_ISDIR (st.st_mode)
|
||||
is_regular = stat.S_ISREG (st.st_mode)
|
||||
|
||||
if is_dir and fn_filter_dir (level, path):
|
||||
files = []
|
||||
for entry in os.listdir (path):
|
||||
path1 = os.path.join (path, entry)
|
||||
files.extend (traverse (fn_filter_dir, fn_filter_regular_file, level + 1, path1))
|
||||
return files
|
||||
|
||||
elif is_regular and fn_filter_regular_file (level, path):
|
||||
return [path]
|
||||
|
||||
else:
|
||||
return []
|
||||
|
||||
# ================================================================
|
||||
# For each ELF file, execute it in the RISC-V simulator
|
||||
|
||||
def do_worker (worker_num, args_dict):
|
||||
tmpdir = "./worker_" + "{0}".format (worker_num)
|
||||
if not os.path.exists (tmpdir):
|
||||
os.mkdir (tmpdir)
|
||||
elif not os.path.isdir (tmpdir):
|
||||
sys.stdout.write ("ERROR: Worker {0}: {1} exists but is not a dir".format (worker_num, tmpdir))
|
||||
return
|
||||
|
||||
os.chdir (tmpdir)
|
||||
sys.stdout.write ("Worker {0} using dir: {1}\n".format (worker_num, tmpdir))
|
||||
|
||||
n_tests = args_dict ['n_tests']
|
||||
filenames = args_dict ['filenames']
|
||||
index = args_dict ['index']
|
||||
results = args_dict ['results']
|
||||
|
||||
num_executed = 0
|
||||
num_passed = 0
|
||||
|
||||
while True:
|
||||
# Get a unique index into the filenames, and get the filename
|
||||
with index.get_lock():
|
||||
my_index = index.value
|
||||
index.value = my_index + 1
|
||||
if my_index >= n_tests:
|
||||
# All done
|
||||
with results.get_lock():
|
||||
results [2 * worker_num] = num_executed
|
||||
results [2 * worker_num + 1] = num_passed
|
||||
return
|
||||
filename = filenames [my_index]
|
||||
|
||||
(message, passed) = do_benchmark (args_dict, filename)
|
||||
num_executed = num_executed + 1
|
||||
|
||||
if passed:
|
||||
num_passed = num_passed + 1
|
||||
pass_fail = "PASS"
|
||||
else:
|
||||
pass_fail = "FAIL"
|
||||
|
||||
message = message + ("Worker {0}: Test: {1} {2} [So far: total {3}, executed {4}, PASS {5}, FAIL {6}]\n"
|
||||
.format (worker_num,
|
||||
os.path.basename (filename),
|
||||
pass_fail,
|
||||
n_tests,
|
||||
num_executed,
|
||||
num_passed,
|
||||
num_executed - num_passed))
|
||||
sys.stdout.write (message)
|
||||
# Create a TAP file to output individual test result in TAP format
|
||||
tap_out = open("../benchmark_report.tap", "a+")
|
||||
tap_out.write(("ok" if passed else "not ok") + " " + str(my_index + 1) + " - " + filenames[my_index] + "\n")
|
||||
tap_out.close()
|
||||
|
||||
# ================================================================
|
||||
# For each ELF file, execute it in the RISC-V simulator
|
||||
|
||||
def do_benchmark (args_dict, full_filename):
|
||||
message = ""
|
||||
|
||||
(dirname, basename) = os.path.split (full_filename)
|
||||
|
||||
# Construct the commands for sub-process execution
|
||||
command1 = [args_dict ['elf_to_hex_exe'], full_filename, "Mem.hex"]
|
||||
|
||||
command2 = [args_dict ['sim_path'], "+tohost"]
|
||||
if (args_dict ['verbosity'] == 1): command2.append ("+v1")
|
||||
elif (args_dict ['verbosity'] == 2): command2.append ("+v2")
|
||||
|
||||
message = message + " Exec:"
|
||||
for x in command1:
|
||||
message = message + (" {0}".format (x))
|
||||
message = message + "\n"
|
||||
|
||||
message = message + (" Exec:")
|
||||
for x in command2:
|
||||
message = message + (" {0}".format (x))
|
||||
message = message + ("\n")
|
||||
|
||||
# Save stdouts in log file
|
||||
log_filename = os.path.join (args_dict ['logs_path'], basename + ".log")
|
||||
message = message + (" Writing log: {0}\n".format (log_filename))
|
||||
|
||||
with open (log_filename, 'w') as fd:
|
||||
completed_process1 = run_command (command1, fd)
|
||||
|
||||
if completed_process1 is not None and completed_process1.returncode == 0:
|
||||
completed_process2 = run_command (command2, fd)
|
||||
passed = completed_process2 is not None and \
|
||||
completed_process2.returncode == 0 and \
|
||||
not completed_process2.stdout.endswith ("FAIL 1")
|
||||
else:
|
||||
passed = False
|
||||
|
||||
# If Tandem Verification trace file was created, save it as well
|
||||
if os.path.exists ("./trace_out.dat"):
|
||||
trace_filename = os.path.join (args_dict ['logs_path'], basename + ".trace_data")
|
||||
os.rename ("./trace_out.dat", trace_filename)
|
||||
message = message + (" Trace output saved in: {0}\n".format (trace_filename))
|
||||
|
||||
return (message, passed)
|
||||
|
||||
# ================================================================
|
||||
# This is a wrapper around 'subprocess.run' because of an annoying
|
||||
# incompatible change in moving from Python 3.5 to 3.6
|
||||
|
||||
def run_command (command, log_fd):
|
||||
command_str = " ".join(command)
|
||||
log_fd.write (f"Running: {command_str}\n")
|
||||
try:
|
||||
python_minor_version = sys.version_info [1]
|
||||
if python_minor_version < 6:
|
||||
# Python 3.5 and earlier
|
||||
result = subprocess.run (args = command,
|
||||
bufsize = 0,
|
||||
stdout = subprocess.PIPE,
|
||||
stderr = subprocess.STDOUT,
|
||||
universal_newlines = True,
|
||||
timeout=timeout)
|
||||
else:
|
||||
# Python 3.6 and later
|
||||
result = subprocess.run (args = command,
|
||||
bufsize = 0,
|
||||
stdout = subprocess.PIPE,
|
||||
stderr = subprocess.STDOUT,
|
||||
encoding='utf-8',
|
||||
timeout=timeout)
|
||||
log_fd.write(f"Finished with exit code {result.returncode}\n")
|
||||
log_fd.write("Stdout:\n")
|
||||
log_fd.write (result.stdout)
|
||||
return result
|
||||
except subprocess.TimeoutExpired:
|
||||
sys.stderr.write(f"TIMEOUT: {command_str} !\n")
|
||||
log_fd.write("TIMEOUT!\n")
|
||||
return None
|
||||
|
||||
# ================================================================
|
||||
# For non-interactive invocations, call main() and use its return value
|
||||
# as the exit code.
|
||||
if __name__ == '__main__':
|
||||
sys.exit (main (sys.argv))
|
||||
@@ -202,12 +202,12 @@ def main (argv = None):
|
||||
# Create a TAP file to output individual test results in TAP format
|
||||
tap_out = open("../isa_test_report.tap", "w")
|
||||
tap_out.write("1.." + str(n_tests) + "\n")
|
||||
tap_out.flush()
|
||||
tap_out.close()
|
||||
|
||||
# Create n workers
|
||||
sys.stdout.write ("Creating {0} workers (sub-processes)\n".format (n_workers))
|
||||
workers = [multiprocessing.Process (target = do_worker,
|
||||
args = (w, args_dict, tap_out))
|
||||
args = (w, args_dict))
|
||||
for w in range (n_workers)]
|
||||
|
||||
# Start the workers
|
||||
@@ -228,9 +228,6 @@ def main (argv = None):
|
||||
num_executed = num_executed + n_e
|
||||
num_passed = num_passed + n_p
|
||||
|
||||
# Close tap_out file
|
||||
tap_out.close()
|
||||
|
||||
# Write final statistics
|
||||
sys.stdout.write ("Total tests: {0} tests\n".format (n_tests))
|
||||
sys.stdout.write ("Executed: {0} tests\n".format (num_executed))
|
||||
@@ -335,7 +332,7 @@ def traverse (fn_filter_dir, fn_filter_regular_file, level, path):
|
||||
# ================================================================
|
||||
# For each ELF file, execute it in the RISC-V simulator
|
||||
|
||||
def do_worker (worker_num, args_dict, tap_out):
|
||||
def do_worker (worker_num, args_dict):
|
||||
tmpdir = "./worker_" + "{0}".format (worker_num)
|
||||
if not os.path.exists (tmpdir):
|
||||
os.mkdir (tmpdir)
|
||||
@@ -362,7 +359,6 @@ def do_worker (worker_num, args_dict, tap_out):
|
||||
if my_index >= n_tests:
|
||||
# All done
|
||||
with results.get_lock():
|
||||
tap_out.flush()
|
||||
results [2 * worker_num] = num_executed
|
||||
results [2 * worker_num + 1] = num_passed
|
||||
return
|
||||
@@ -386,7 +382,10 @@ def do_worker (worker_num, args_dict, tap_out):
|
||||
num_passed,
|
||||
num_executed - num_passed))
|
||||
sys.stdout.write (message)
|
||||
# Create a TAP file to output individual test result in TAP format
|
||||
tap_out = open("../isa_test_report.tap", "a+")
|
||||
tap_out.write(("ok" if passed else "not ok") + " " + str(my_index + 1) + " - " + filenames[my_index] + "\n")
|
||||
tap_out.close()
|
||||
|
||||
# ================================================================
|
||||
# For each ELF file, execute it in the RISC-V simulator
|
||||
|
||||
1
Tests/benchmarks
Submodule
1
Tests/benchmarks
Submodule
Submodule Tests/benchmarks added at 1091c9b98e
@@ -25,6 +25,7 @@ help:
|
||||
@echo ''
|
||||
@echo ' make test Runs simulation executable on rv32ui-p-add or rv64ui-p-add'
|
||||
@echo ' make isa_tests Runs simulation executable on all relevant standard RISC-V ISA tests'
|
||||
@echo ' make benchmarks Runs simulation executable on a set of benchmarks'
|
||||
@echo ''
|
||||
@echo ' make clean Remove intermediate build-files unnecessary for execution'
|
||||
@echo ' make full_clean Restore to pristine state (pre-building anything)'
|
||||
@@ -96,6 +97,16 @@ isa_tests:
|
||||
$(REPO)/Tests/Run_regression.py ./exe_HW_sim $(REPO) ./Logs $(ARCH)
|
||||
@echo "Finished running regressions; saved logs in Logs/"
|
||||
|
||||
# ================================================================
|
||||
# Benchmarks
|
||||
|
||||
.PHONY: benchmarks
|
||||
benchmarks:
|
||||
@echo "Running benchmarks; saving logs in Logs/"
|
||||
$(REPO)/Tests/Run_benchmarks.py ./exe_HW_sim $(REPO) ./Logs
|
||||
@echo "Finished running benchmarks"
|
||||
$(REPO)/Tests/benchmarks/report_log.sh Logs/*.bin.log
|
||||
|
||||
# ================================================================
|
||||
# Generate Bluespec CHERI tag controller source file
|
||||
CAPSIZE = 128
|
||||
|
||||
@@ -337,6 +337,8 @@ module mkCore#(CoreId coreId)(Core);
|
||||
endinterface);
|
||||
MMIOCore mmio <- mkMMIOCore(mmioInIfc);
|
||||
|
||||
PulseWire commitRedirect <- mkPulseWire;
|
||||
|
||||
// fix point module to instantiate other function units
|
||||
module mkCoreFixPoint#(CoreFixPoint fix)(CoreFixPoint);
|
||||
// spec update
|
||||
@@ -420,7 +422,7 @@ module mkCore#(CoreId coreId)(Core);
|
||||
method setRegReadyAggr = writeAggr(aluWrAggrPort(i));
|
||||
interface sendBypass = sendBypassIfc;
|
||||
method writeRegFile = writeCons(aluWrConsPort(i));
|
||||
method Action redirect(CapMem new_pc, SpecTag spec_tag, InstTag inst_tag, SpecBits spec_bits);
|
||||
method Action redirect(CapMem new_pc, SpecTag spec_tag, InstTag inst_tag, SpecBits spec_bits) if (!commitRedirect);
|
||||
if (verbose) begin
|
||||
$display("[ALU redirect - %d] ", i, fshow(new_pc),
|
||||
"; ", fshow(spec_tag), "; ", fshow(inst_tag));
|
||||
@@ -526,6 +528,7 @@ module mkCore#(CoreId coreId)(Core);
|
||||
interface memExeIfc = memExe;
|
||||
method Action killAll;
|
||||
globalSpecUpdate.incorrectSpec(True, ?, ?, 0);
|
||||
commitRedirect.send();
|
||||
endmethod
|
||||
interface doStatsIfc = doStatsReg;
|
||||
method pendingIncorrectSpec = globalSpecUpdate.pendingIncorrectSpec;
|
||||
|
||||
@@ -36,6 +36,8 @@ import Vector::*;
|
||||
import BuildVector::*;
|
||||
import ProcTypes::*;
|
||||
|
||||
Bool verbose = False;
|
||||
|
||||
typedef enum {
|
||||
HIT = 1'b0, MISS = 1'b1
|
||||
} HitOrMiss deriving (Bits, Eq, FShow);
|
||||
@@ -193,7 +195,7 @@ module mkSingleWindowL1LLPrefetcher(Prefetcher);
|
||||
method ActionValue#(Addr) getNextPrefetchAddr if (nextToAsk != rangeEnd);
|
||||
nextToAsk <= nextToAsk + 1;
|
||||
let retAddr = Addr'{nextToAsk, '0}; //extend cache line address to regular address
|
||||
if(verbose) $display("%t Prefetcher getNextPrefetchAddr requesting %h", $time, retAddr);
|
||||
if (verbose) $display("%t Prefetcher getNextPrefetchAddr requesting %h", $time, retAddr);
|
||||
return retAddr;
|
||||
endmethod
|
||||
endmodule
|
||||
@@ -446,13 +448,13 @@ module mkTargetTable(TargetTable#(narrowTableSize, wideTableSize)) provisos
|
||||
if (narrowTable[narrowIdx][0] matches tagged Valid .entry
|
||||
&&& entry.tag == addr[31:valueOf(narrowTableIdxBits)]) begin
|
||||
narrowTable[narrowIdx][0] <= Invalid;
|
||||
//$display("%t found narrow table entry %h", $time, addr + signExtend(pack(entry.distance)));
|
||||
//if (verbose) $display("%t found narrow table entry %h", $time, addr + signExtend(pack(entry.distance)));
|
||||
return Valid(addr + signExtend(pack(entry.distance)));
|
||||
end
|
||||
else if (wideTable[wideIdx][0] matches tagged Valid .entry
|
||||
&&& entry.tag == addr[31:valueOf(wideTableIdxBits)]) begin
|
||||
wideTable[wideIdx][0] <= Invalid;
|
||||
//$display("%t found wide table entry %h", $time, entry.target);
|
||||
//if (verbose) $display("%t found wide table entry %h", $time, entry.target);
|
||||
return Valid(entry.target);
|
||||
end
|
||||
else
|
||||
@@ -620,12 +622,12 @@ module mkTargetTableDouble(TargetTableDouble#(narrowTableSize, wideTableSize)) p
|
||||
actionvalue
|
||||
if (narrowWrapped matches tagged Valid .narrow
|
||||
&&& narrowTagMatch(addrHash, narrow)) begin
|
||||
//$display("%t found narrow table entry %h", $time, addr + signExtend(pack(narrow.distance)));
|
||||
//if (verbose) $display("%t found narrow table entry %h", $time, addr + signExtend(pack(narrow.distance)));
|
||||
return Valid(addr + signExtend(pack(narrow.distance)));
|
||||
end
|
||||
else if (wideWrapped matches tagged Valid .wide
|
||||
&&& wideTagMatch(addrHash, wide)) begin
|
||||
//$display("%t found wide table entry %h", $time, wide.target);
|
||||
//if (verbose) $display("%t found wide table entry %h", $time, wide.target);
|
||||
return Valid(wide.target);
|
||||
end
|
||||
else
|
||||
@@ -690,7 +692,7 @@ module mkTargetTableDouble(TargetTableDouble#(narrowTableSize, wideTableSize)) p
|
||||
entry.distance = truncate(distance);
|
||||
|
||||
if (Valid(entry) != lastMissNarrowMRUEntry) begin
|
||||
//$display("%t Recording miss -- modifying narrow table", $time);
|
||||
//if (verbose) $display("%t Recording miss -- modifying narrow table", $time);
|
||||
//Maintain the property that one address can only have
|
||||
// at most 2 of 4 table entries for it.
|
||||
//Shift narrow table entries down, storing in MRU.
|
||||
@@ -710,7 +712,7 @@ module mkTargetTableDouble(TargetTableDouble#(narrowTableSize, wideTableSize)) p
|
||||
entry.target = currAddr;
|
||||
|
||||
if (Valid(entry) != lastMissWideMRUEntry) begin
|
||||
//$display("%t Recording miss -- modifying wide table", $time);
|
||||
//if (verbose) $display("%t Recording miss -- modifying wide table", $time);
|
||||
wideTableMRU.wrReq(idx, Valid(entry));
|
||||
wideTableLRU.wrReq(idx, lastMissWideMRUEntry);
|
||||
Bit#(narrowTableIdxBits) narrowIdx = truncate(lastMissAddrHash);
|
||||
@@ -748,9 +750,9 @@ module mkTargetTableDouble(TargetTableDouble#(narrowTableSize, wideTableSize)) p
|
||||
//Update the entries for the last miss to point to this one
|
||||
writeMissEntry(addr);
|
||||
//Save the raw table entries
|
||||
//$display("idx: %x", addrHash);
|
||||
//$display("%t Read resp: nMRU: ", fshow(narrowTableMRU.rdResp), "wMRU: ", fshow(wideTableMRU.rdResp));
|
||||
//$display("%t Read resp: nLRU: ", fshow(narrowTableLRU.rdResp), "wLRU: ", fshow(wideTableLRU.rdResp));
|
||||
//if (verbose) $display("idx: %x", addrHash);
|
||||
//if (verbose) $display("%t Read resp: nMRU: ", fshow(narrowTableMRU.rdResp), "wMRU: ", fshow(wideTableMRU.rdResp));
|
||||
//if (verbose) $display("%t Read resp: nLRU: ", fshow(narrowTableLRU.rdResp), "wLRU: ", fshow(wideTableLRU.rdResp));
|
||||
lastMissWideMRUEntry <= wideTableMRU.rdResp;
|
||||
lastMissNarrowMRUEntry <= narrowTableMRU.rdResp;
|
||||
lastMissWideLRUEntry <= wideTableLRU.rdResp;
|
||||
@@ -1036,7 +1038,7 @@ module mkBRAMMarkovPrefetcher(Prefetcher) provisos
|
||||
|
||||
if (hitMiss == MISS) begin
|
||||
//Don't start markov chain if its very recent
|
||||
//$display("%t Prefetcher start new chain with %h", $time, addr);
|
||||
//if (verbose) $display("%t Prefetcher start new chain with %h", $time, addr);
|
||||
chainNextToLookup <= cl;
|
||||
chainNumberToPrefetch <= fromInteger(valueOf(maxChainLength));
|
||||
end
|
||||
@@ -1291,7 +1293,7 @@ provisos(
|
||||
strideTable.deqRdResp;
|
||||
StrideEntry seNext = se;
|
||||
Bit#(13) observedStride = {1'b0, addr[11:0]} - {1'b0, se.lastAddr};
|
||||
if (verbose) $writeh("%t Stride Prefetcher updateStrideEntry ", $time,
|
||||
if (verbose) $display("%t Stride Prefetcher updateStrideEntry ", $time,
|
||||
fshow(hitMiss), " ", addr,
|
||||
". Entry ", index, " state is ", fshow(se.state));
|
||||
if (se.state == EMPTY) begin
|
||||
@@ -1415,7 +1417,7 @@ provisos(
|
||||
);
|
||||
Bool verbose = False;
|
||||
RWBramCore#(strideTableIndexT, StrideEntry2) strideTable <- mkRWBramCoreForwarded;
|
||||
FIFOF#(Tuple3#(Addr, Bit#(16), HitOrMiss)) memAccesses <- mkSizedBypassFIFOF(8);
|
||||
FIFOF#(Tuple3#(Addr, Bit#(16), HitOrMiss)) memAccesses <- mkUGSizedFIFOF(8);
|
||||
Reg#(Tuple3#(Addr, Bit#(16), HitOrMiss)) rdRespEntry <- mkReg(?);
|
||||
|
||||
Fifo#(8, Addr) addrToPrefetch <- mkOverflowPipelineFifo;
|
||||
@@ -1423,7 +1425,7 @@ provisos(
|
||||
Reg#(Maybe#(Bit#(2))) cLinesPrefetchedLatest <- mkReg(?);
|
||||
PulseWire holdReadReq <- mkPulseWire;
|
||||
|
||||
rule sendReadReq if (!holdReadReq);
|
||||
rule sendReadReq if (!holdReadReq && memAccesses.notEmpty);
|
||||
match {.addr, .pcHash, .hitMiss} = memAccesses.first;
|
||||
if (verbose) $display("%t Sending read req for %h!", $time, pcHash);
|
||||
strideTable.rdReq(truncate(pcHash));
|
||||
@@ -1445,7 +1447,7 @@ provisos(
|
||||
strideTable.deqRdResp;
|
||||
StrideEntry2 seNext = se;
|
||||
Int#(12) observedStride = unpack(addr[11:0] - se.lastAddr);
|
||||
if (verbose) $writeh("%t Stride Prefetcher updateStrideEntry ", $time,
|
||||
if (verbose) $display("%t Stride Prefetcher updateStrideEntry ", $time,
|
||||
fshow(hitMiss), " ", addr,
|
||||
". Entry ", index, " state is ", fshow(se.state));
|
||||
if (se.state == INIT && observedStride != 0) begin
|
||||
@@ -1548,7 +1550,7 @@ provisos(
|
||||
endrule
|
||||
|
||||
method Action reportAccess(Addr addr, Bit#(16) pcHash, HitOrMiss hitMiss);
|
||||
memAccesses.enq(tuple3 (addr, pcHash, hitMiss));
|
||||
if (memAccesses.notFull) memAccesses.enq(tuple3 (addr, pcHash, hitMiss));
|
||||
endmethod
|
||||
|
||||
method ActionValue#(Addr) getNextPrefetchAddr;
|
||||
@@ -1726,7 +1728,7 @@ provisos(
|
||||
strideTable.deqRdResp;
|
||||
StrideEntryAdaptive seNext = se;
|
||||
Bit#(13) observedStride = {1'b0, addr[11:0]} - {1'b0, se.lastAddr};
|
||||
if (verbose) $writeh("%t Stride Prefetcher updateStrideEntry ", $time,
|
||||
if (verbose) $display("%t Stride Prefetcher updateStrideEntry ", $time,
|
||||
fshow(hitMiss), " ", addr,
|
||||
". Entry ", index, " state is ", fshow(se.state));
|
||||
if (se.state == EMPTY) begin
|
||||
@@ -1946,7 +1948,7 @@ module mkLLIPrefetcher(Prefetcher);
|
||||
`endif
|
||||
return m;
|
||||
endmodule
|
||||
|
||||
(* synthesize *)
|
||||
module mkL1DPrefetcher(PCPrefetcher);
|
||||
`ifdef DATA_PREFETCHER_IN_L1
|
||||
`ifdef DATA_PREFETCHER_BLOCK
|
||||
|
||||
@@ -297,7 +297,7 @@ deriving (Eq, FShow, Bits);
|
||||
`endif
|
||||
|
||||
module mkCommitStage#(CommitInput inIfc)(CommitStage);
|
||||
Bool verbose = False;
|
||||
Bool verbose = True;
|
||||
|
||||
Integer verbosity = 1; // Bluespec: for lightweight verbosity trace
|
||||
|
||||
|
||||
@@ -45,7 +45,6 @@ import Bht::*;
|
||||
import GSelectPred::*;
|
||||
import GSharePred::*;
|
||||
import TourPred::*;
|
||||
import TourPredSecure::*;
|
||||
import Ras::*;
|
||||
|
||||
export DirPredTrainInfo(..);
|
||||
|
||||
@@ -26,6 +26,7 @@ import Vector::*;
|
||||
import Ehr::*;
|
||||
import Types::*;
|
||||
import ProcTypes::*;
|
||||
import ConfigReg::*;
|
||||
|
||||
typedef struct {
|
||||
Epoch curEp;
|
||||
@@ -53,47 +54,44 @@ endinterface
|
||||
|
||||
(* synthesize *)
|
||||
module mkEpochManager(EpochManager);
|
||||
Reg#(Epoch) curr_epoch <- mkReg(0);
|
||||
Reg#(Epoch) prev_checked_epoch <- mkReg(0);
|
||||
Reg#(Epoch) curr_epoch <- mkConfigReg(0);
|
||||
Reg#(Epoch) prev_checked_epoch <- mkConfigReg(0);
|
||||
Epoch next_epoch = (curr_epoch== fromInteger(valueOf(NumEpochs)-1)) ? 0 : (curr_epoch+1);
|
||||
|
||||
// epochs in the core are within range [prev_checked_epoch, curr_epoch]
|
||||
// prev_checked_epoch can be updated in a lazy way
|
||||
Vector#(SupSize, Ehr#(2, Maybe#(Epoch))) updatePrevEn <- replicateM(mkEhr(Invalid));
|
||||
Vector#(SupSize, RWire#(Epoch)) updatePrevEn <- replicateM(mkRWire);
|
||||
|
||||
(* fire_when_enabled, no_implicit_conditions *)
|
||||
rule canon_prev_checked_epoch;
|
||||
Vector#(SupSize, Maybe#(Epoch)) updates = readVEhr(1, updatePrevEn);
|
||||
Vector#(SupSize, Maybe#(Epoch)) updates = ?;
|
||||
for (Integer i = 0; i < valueof(SupSize); i = i + 1) updates[i] = updatePrevEn[i].wget();
|
||||
// find the last update
|
||||
if(find(isValid, reverse(updates)) matches tagged Valid .upd) begin
|
||||
doAssert(isValid(upd), "must be valid");
|
||||
prev_checked_epoch <= validValue(upd);
|
||||
end
|
||||
// reset EHR
|
||||
for(Integer i = 0; i < valueof(SupSize); i = i+1) begin
|
||||
updatePrevEn[i][1] <= Invalid;
|
||||
end
|
||||
endrule
|
||||
|
||||
Vector#(SupSize, EM_updatePrevEpoch) updateIfc;
|
||||
for(Integer i = 0; i < valueof(SupSize); i = i+1) begin
|
||||
updateIfc[i] = (interface EM_updatePrevEpoch;
|
||||
method Action update(Epoch e);
|
||||
updatePrevEn[i][0] <= Valid (e); // record update action
|
||||
updatePrevEn[i].wset(e); // record update action
|
||||
`ifdef BSIM
|
||||
// sanity check
|
||||
Epoch checkedEpoch = prev_checked_epoch;
|
||||
for(Integer j = 0; j < i; j = j+1) begin
|
||||
if(updatePrevEn[j][1] matches tagged Valid .ep) begin
|
||||
checkedEpoch = ep;
|
||||
end
|
||||
end
|
||||
if(checkedEpoch <= curr_epoch) begin
|
||||
doAssert(checkedEpoch <= e && e <= curr_epoch, "e in [checkedEpoch, curr_epoch]");
|
||||
end
|
||||
else begin
|
||||
doAssert(checkedEpoch <= e || e <= curr_epoch, "e in [checkedEpoch, max] + [0, curr_epoch]");
|
||||
end
|
||||
//Epoch checkedEpoch = prev_checked_epoch;
|
||||
//for(Integer j = 0; j < i; j = j+1) begin
|
||||
// if(updatePrevEn[j][1] matches tagged Valid .ep) begin
|
||||
// checkedEpoch = ep;
|
||||
// end
|
||||
//end
|
||||
//if(checkedEpoch <= curr_epoch) begin
|
||||
// doAssert(checkedEpoch <= e && e <= curr_epoch, "e in [checkedEpoch, curr_epoch]");
|
||||
//end
|
||||
//else begin
|
||||
// doAssert(checkedEpoch <= e || e <= curr_epoch, "e in [checkedEpoch, max] + [0, curr_epoch]");
|
||||
//end
|
||||
`endif
|
||||
endmethod
|
||||
endinterface);
|
||||
|
||||
@@ -48,6 +48,8 @@ import HasSpecBits::*;
|
||||
import Vector::*;
|
||||
import Assert::*;
|
||||
import Ehr::*;
|
||||
import ConfigReg::*;
|
||||
import SpecialRegs::*;
|
||||
import RevertingVirtualReg::*;
|
||||
`ifdef RVFI_DII
|
||||
import RVFI_DII_Types::*;
|
||||
@@ -260,29 +262,29 @@ module mkReorderBufferRowEhr(ReorderBufferRowEhr#(aluExeNum, fpuMulDivExeNum)) p
|
||||
Integer traceBundle_deqLSQ_port = valueof(fpuMulDivExeNum) + valueof(aluExeNum);
|
||||
Integer traceBundle_enq_port = 1 + traceBundle_deqLSQ_port;
|
||||
|
||||
Reg#(CapMem) pc <- mkRegU;
|
||||
Reg #(Bit #(32)) orig_inst <- mkRegU;
|
||||
Reg#(IType) iType <- mkRegU;
|
||||
Reg #(Maybe #(ArchRIndx)) rg_dst_reg <- mkRegU;
|
||||
Reg#(CapMem) pc <- mkConfigRegU;
|
||||
Reg #(Bit #(32)) orig_inst <- mkConfigRegU;
|
||||
Reg#(IType) iType <- mkConfigRegU;
|
||||
Reg #(Maybe #(ArchRIndx)) rg_dst_reg <- mkConfigRegU;
|
||||
`ifdef INCLUDE_TANDEM_VERIF
|
||||
Reg #(Data) rg_dst_data <- mkRegU;
|
||||
Reg #(Data) rg_store_data <- mkRegU;
|
||||
Reg #(ByteEn) rg_store_data_BE <- mkRegU;
|
||||
Reg #(Data) rg_dst_data <- mkConfigRegU;
|
||||
Reg #(Data) rg_store_data <- mkConfigRegU;
|
||||
Reg #(ByteEn) rg_store_data_BE <- mkConfigRegU;
|
||||
`endif
|
||||
Reg#(Maybe#(CSR)) csr <- mkRegU;
|
||||
Reg#(Maybe#(SCR)) scr <- mkRegU;
|
||||
Reg#(Bool) claimed_phy_reg <- mkRegU;
|
||||
Ehr#(TAdd#(2, aluExeNum), Maybe#(Trap)) trap <- mkEhr(?);
|
||||
Ehr#(TAdd#(2, aluExeNum), PPCVAddrCSRData) ppc_vaddr_csrData <- mkEhr(?);
|
||||
Ehr#(TAdd#(1, fpuMulDivExeNum), Bit#(5)) fflags <- mkEhr(?);
|
||||
Reg#(Bool) will_dirty_fpu_state <- mkRegU;
|
||||
Ehr#(TAdd#(3, TAdd#(fpuMulDivExeNum, aluExeNum)), RobInstState) rob_inst_state <- mkEhr(?);
|
||||
Reg#(LdStQTag) lsqTag <- mkRegU;
|
||||
Ehr#(2, Maybe#(LdKilledBy)) ldKilled <- mkEhr(?);
|
||||
Ehr#(3, Bool) memAccessAtCommit <- mkEhr(?);
|
||||
Ehr#(2, Bool) lsqAtCommitNotified <- mkEhr(?);
|
||||
Ehr#(2, Bool) nonMMIOStDone <- mkEhr(?);
|
||||
Reg#(Bool) epochIncremented <- mkRegU;
|
||||
Reg#(Maybe#(CSR)) csr <- mkConfigRegU;
|
||||
Reg#(Maybe#(SCR)) scr <- mkConfigRegU;
|
||||
Reg#(Bool) claimed_phy_reg <- mkConfigRegU;
|
||||
Ehr#(TAdd#(2, aluExeNum), Maybe#(Trap)) trap <- mkRegOR(?);
|
||||
Ehr#(TAdd#(2, aluExeNum), PPCVAddrCSRData) ppc_vaddr_csrData <- mkRegOR(?);
|
||||
Ehr#(TAdd#(1, fpuMulDivExeNum), Bit#(5)) fflags <- mkRegOR(?);
|
||||
Reg#(Bool) will_dirty_fpu_state <- mkConfigRegU;
|
||||
Ehr#(TAdd#(3, TAdd#(fpuMulDivExeNum, aluExeNum)), RobInstState) rob_inst_state <- mkRegOR(?);
|
||||
Reg#(LdStQTag) lsqTag <- mkConfigRegU;
|
||||
Ehr#(2, Maybe#(LdKilledBy)) ldKilled <- mkRegOR(?);
|
||||
Ehr#(3, Bool) memAccessAtCommit <- mkRegOR(?);
|
||||
Ehr#(2, Bool) lsqAtCommitNotified <- mkRegOR(?);
|
||||
Ehr#(2, Bool) nonMMIOStDone <- mkRegOR(?);
|
||||
Reg#(Bool) epochIncremented <- mkConfigRegU;
|
||||
Ehr#(3, SpecBits) spec_bits <- mkEhr(?);
|
||||
`ifdef RVFI_DII
|
||||
Reg#(Dii_Parcel_Id) dii_pid <- mkRegU;
|
||||
@@ -1131,8 +1133,8 @@ module mkSupReorderBuffer#(
|
||||
for(Integer i = 0; i < valueof(SupSize); i = i+1) begin
|
||||
SupWaySel way = getDeqFifoWay(fromInteger(i)); // FIFO[way] is used by deq port i
|
||||
Bool can_deq = can_deq_fifo[way] &&
|
||||
deq_SB_wrongSpec && // ordering: < wrongSpec
|
||||
all(id, readVReg(deq_SB_enq)); // ordering: < enq
|
||||
deq_SB_wrongSpec /*&& // ordering: < wrongSpec
|
||||
all(id, readVReg(deq_SB_enq))*/; // ordering: < enq
|
||||
deqIfc[i] = (interface ROB_DeqPort;
|
||||
method Bool canDeq = can_deq;
|
||||
method Action deq if(can_deq);
|
||||
|
||||
Reference in New Issue
Block a user