mirror of
https://github.com/openhwgroup/cvw
synced 2025-02-11 06:05:49 +00:00
Merge branch 'main' of https://github.com/openhwgroup/cvw
This commit is contained in:
commit
e9e856d2a2
36
.github/workflows/lint.yml
vendored
Normal file
36
.github/workflows/lint.yml
vendored
Normal file
@ -0,0 +1,36 @@
|
||||
name: Lint
|
||||
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- '**/*.py'
|
||||
- 'bin/*'
|
||||
- 'sim/vcs/run_vcs'
|
||||
- '.ruff.toml'
|
||||
- '!addins/*'
|
||||
- '!tests/wally-riscv-arch-test/riscv-test-suite/rv64i_m/Q/*'
|
||||
- '!tests/fp/quad/fpdatasetgen.py'
|
||||
pull_request:
|
||||
paths:
|
||||
- '**/*.py'
|
||||
- 'bin/*'
|
||||
- 'sim/vcs/run_vcs'
|
||||
- '.ruff.toml'
|
||||
- '!addins/*'
|
||||
- '!tests/wally-riscv-arch-test/riscv-test-suite/rv64i_m/Q/*'
|
||||
- '!tests/fp/quad/fpdatasetgen.py'
|
||||
|
||||
jobs:
|
||||
lint:
|
||||
name: Python ${{matrix.version}} lint
|
||||
strategy:
|
||||
matrix:
|
||||
version: [39, 312] # Test on oldest and newest verions used in wally-package-install.sh
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Set Python version
|
||||
run: sed -i '/^target-version/c\target-version = "py${{matrix.version}}"' .ruff.toml
|
||||
- name: Run ruff
|
||||
uses: astral-sh/ruff-action@v3
|
31
.ruff.toml
Normal file
31
.ruff.toml
Normal file
@ -0,0 +1,31 @@
|
||||
# Lint all .py files and extra python scripts without extensions
|
||||
include = ["*.py", "bin/wsim", "bin/regression-wally", "bin/iterelf", "sim/vcs/run_vcs"]
|
||||
exclude = ["addins/*", "tests/wally-riscv-arch-test/riscv-test-suite/rv64i_m/Q/*", "tests/fp/quad/fpdatasetgen.py"]
|
||||
|
||||
# Target oldest version of Python used (Python 3.9 for Ubuntu 20.04 LTS)
|
||||
target-version = "py39"
|
||||
|
||||
line-length=250
|
||||
|
||||
[lint]
|
||||
select = [
|
||||
"F", # various basic rules
|
||||
"E101", # indentation contains mixed spaces and tabs
|
||||
"E4", # imports
|
||||
"E7", # various improvements
|
||||
"E9", # error
|
||||
"W1", # tabs used instead of spaces
|
||||
"W292", # no newline at end of file
|
||||
"UP", # Upgraded version available in newer Python
|
||||
"EXE", # Executable file shebangs
|
||||
"Q003", # Avoidable escaped quotes
|
||||
"Q004", # Unnecessary esacpe character
|
||||
"RUF", # Ruff specific rules
|
||||
]
|
||||
|
||||
ignore = [
|
||||
"E701", "E702", # multiple statements on one line
|
||||
"E722", # do not use bare 'except'
|
||||
"E74", # ambiguous name
|
||||
"RUF005", # iterable unpacking in list
|
||||
]
|
@ -1,4 +1,4 @@
|
||||

|
||||
[](https://github.com/openhwgroup/cvw/actions/workflows/install.yml)
|
||||
|
||||
# core-v-wally
|
||||
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit 66b675017878032974c537ab7aa81758b9812530
|
||||
Subproject commit 44278d9a918dbc337ac214cd5dba5f71aa26dcfa
|
@ -65,10 +65,7 @@ with open(resultfile, mode='w', newline='') as csvfile:
|
||||
|
||||
# Loop through each architecture and run the make commands
|
||||
for arch in arch_list:
|
||||
if(str in arch):
|
||||
xlen_value='32'
|
||||
else:
|
||||
xlen_value='64'
|
||||
xlen_value = "32" if str in arch else "64"
|
||||
os.system("make clean")
|
||||
make_all = f"make all XLEN={xlen_value} ARCH={arch}"
|
||||
os.system(make_all)
|
||||
|
@ -30,12 +30,8 @@ def tabulate_arch_sweep(directory):
|
||||
file = case+"_"+arch+".json"
|
||||
file_path = os.path.join(directory, file)
|
||||
lines = []
|
||||
try:
|
||||
f = open(file_path, "r")
|
||||
with open(file_path) as f:
|
||||
lines = f.readlines()
|
||||
except:
|
||||
f.close()
|
||||
#print(file_path+" does not exist")
|
||||
for line in lines:
|
||||
#print("File: "+file+" Line: "+line)
|
||||
#p = re.compile('".*" : .*,')
|
||||
@ -43,8 +39,8 @@ def tabulate_arch_sweep(directory):
|
||||
match = re.search(p, line)
|
||||
if match:
|
||||
prog = match.group(1)
|
||||
result = match.group(2);
|
||||
d[arch][prog] = result;
|
||||
result = match.group(2)
|
||||
d[arch][prog] = result
|
||||
#print(match.group(1)+" " + match.group(2))
|
||||
f.close()
|
||||
for arch in [""] + archs:
|
||||
@ -53,7 +49,7 @@ def tabulate_arch_sweep(directory):
|
||||
for prog in d[archs[0]]:
|
||||
print(prog, end="\t")
|
||||
for arch in archs:
|
||||
entry = d[arch].get(prog, "n/a");
|
||||
entry = d[arch].get(prog, "n/a")
|
||||
print (entry, end="\t")
|
||||
print("")
|
||||
print("New geo mean", end="\t")
|
||||
|
@ -10,13 +10,13 @@ from plotly.subplots import make_subplots
|
||||
|
||||
debug = True
|
||||
|
||||
def loadCoremark():
|
||||
def loadCoremark(coremarkData):
|
||||
"""loads the coremark data dictionary"""
|
||||
coremarkPath = "riscv-coremark/work/coremark.sim.log"
|
||||
|
||||
keywordlist = ["CoreMark 1.0", "CoreMark Size", "MTIME", "MINSTRET", "Branches Miss Predictions", "BTB Misses"]
|
||||
for keyword in keywordlist:
|
||||
bashInst = "cat " + coremarkPath + " | grep \"" + keyword + "\" | cut -d \':\' -f 2 | cut -d \" \" -f 2 | tail -1"
|
||||
bashInst = "cat " + coremarkPath + ' | grep "' + keyword + "\" | cut -d ':' -f 2 | cut -d \" \" -f 2 | tail -1"
|
||||
result = subprocess.run(bashInst, stdout=subprocess.PIPE, shell=True)
|
||||
if (debug): print(result)
|
||||
coremarkData[keyword] = int(result.stdout)
|
||||
@ -25,7 +25,7 @@ def loadCoremark():
|
||||
|
||||
def loadEmbench(embenchPath, embenchData):
|
||||
"""loads the embench data dictionary"""
|
||||
f = open(embenchPath)
|
||||
with open(embenchPath) as f:
|
||||
embenchData = json.load(f)
|
||||
if (debug): print(embenchData)
|
||||
return embenchData
|
||||
@ -93,7 +93,7 @@ def main():
|
||||
embenchSpeedOpt_SpeedData = {}
|
||||
embenchSizeOpt_SizeData = {}
|
||||
embenchSpeedOpt_SizeData = {}
|
||||
# coremarkData = loadCoremark()
|
||||
coremarkData = loadCoremark(coremarkData)
|
||||
embenchSpeedOpt_SpeedData = loadEmbench("embench/wallySpeedOpt_speed.json", embenchSpeedOpt_SpeedData)
|
||||
embenchSizeOpt_SpeedData = loadEmbench("embench/wallySizeOpt_speed.json", embenchSizeOpt_SpeedData)
|
||||
embenchSpeedOpt_SizeData = loadEmbench("embench/wallySpeedOpt_size.json", embenchSpeedOpt_SizeData)
|
||||
|
@ -44,6 +44,7 @@
|
||||
import math
|
||||
import argparse
|
||||
import os
|
||||
import sys
|
||||
|
||||
class CacheLine:
|
||||
def __init__(self):
|
||||
@ -52,8 +53,8 @@ class CacheLine:
|
||||
self.dirty = False
|
||||
|
||||
def __str__(self):
|
||||
string = "(V: " + str(self.valid) + ", D: " + str(self.dirty)
|
||||
string += ", Tag: " + str(hex(self.tag)) + ")"
|
||||
string = f"(V: {self.valid}, D: {self.dirty}"
|
||||
string += f", Tag: {hex(self.tag)})"
|
||||
return string
|
||||
|
||||
def __repr__(self):
|
||||
@ -72,7 +73,7 @@ class Cache:
|
||||
self.ways = []
|
||||
for i in range(numways):
|
||||
self.ways.append([])
|
||||
for j in range(numsets):
|
||||
for _ in range(numsets):
|
||||
self.ways[i].append(CacheLine())
|
||||
|
||||
self.pLRU = []
|
||||
@ -92,7 +93,8 @@ class Cache:
|
||||
line = self.ways[waynum][setnum]
|
||||
if line.tag == tag and line.valid:
|
||||
line.dirty = 0
|
||||
if invalidate: line.valid = 0
|
||||
if invalidate:
|
||||
line.valid = 0
|
||||
|
||||
# invalidates the cache by setting all valid bits to False
|
||||
def invalidate(self):
|
||||
@ -103,7 +105,7 @@ class Cache:
|
||||
# resets the pLRU to a fresh 2-D array of 0s
|
||||
def clear_pLRU(self):
|
||||
self.pLRU = []
|
||||
for i in range(self.numsets):
|
||||
for _ in range(self.numsets):
|
||||
self.pLRU.append([0]*(self.numways-1))
|
||||
|
||||
# splits the given address into tag, set, and offset
|
||||
@ -158,7 +160,7 @@ class Cache:
|
||||
tree = self.pLRU[setnum]
|
||||
bottomrow = (self.numways - 1)//2
|
||||
index = (waynum // 2) + bottomrow
|
||||
tree[index] = int(not (waynum % 2))
|
||||
tree[index] = int(not waynum % 2)
|
||||
while index > 0:
|
||||
parent = (index-1) // 2
|
||||
tree[parent] = index % 2
|
||||
@ -191,9 +193,9 @@ class Cache:
|
||||
def __str__(self):
|
||||
string = ""
|
||||
for i in range(self.numways):
|
||||
string += "Way " + str(i) + ": "
|
||||
string += f"Way {i}: "
|
||||
for line in self.ways[i]:
|
||||
string += str(line) + ", "
|
||||
string += f"{line}, "
|
||||
string += "\n\n"
|
||||
return string
|
||||
|
||||
@ -201,7 +203,7 @@ class Cache:
|
||||
return self.__str__()
|
||||
|
||||
|
||||
def main():
|
||||
def parseArgs():
|
||||
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')
|
||||
@ -211,8 +213,9 @@ def main():
|
||||
parser.add_argument('-v', "--verbose", action='store_true', help="verbose/full-trace mode")
|
||||
parser.add_argument('-p', "--perf", action='store_true', help="Report hit/miss ratio")
|
||||
parser.add_argument('-d', "--dist", action='store_true', help="Report distribution of operations")
|
||||
return parser.parse_args()
|
||||
|
||||
args = parser.parse_args()
|
||||
def main(args):
|
||||
cache = Cache(args.numlines, args.numways, args.addrlen, args.taglen)
|
||||
extfile = os.path.expanduser(args.file)
|
||||
mismatches = 0
|
||||
@ -227,7 +230,7 @@ def main():
|
||||
atoms = 0
|
||||
totalops = 0
|
||||
|
||||
with open(extfile, "r") as f:
|
||||
with open(extfile) as f:
|
||||
for ln in f:
|
||||
ln = ln.strip()
|
||||
lninfo = ln.split()
|
||||
@ -257,7 +260,7 @@ def main():
|
||||
IsCBOClean = lninfo[1] != 'C'
|
||||
cache.cbo(addr, IsCBOClean)
|
||||
if args.verbose:
|
||||
print(lninfo[1]);
|
||||
print(lninfo[1])
|
||||
else:
|
||||
addr = int(lninfo[0], 16)
|
||||
iswrite = lninfo[1] == 'W' or lninfo[1] == 'A' or lninfo[1] == 'Z'
|
||||
@ -281,14 +284,14 @@ def main():
|
||||
elif lninfo[1] == 'A':
|
||||
atoms += 1
|
||||
|
||||
if not result == lninfo[2]:
|
||||
print("Result mismatch at address", lninfo[0]+ ". Wally:", lninfo[2]+", Sim:", result)
|
||||
if result != lninfo[2]:
|
||||
print(f"Result mismatch at address {lninfo[0]}. Wally: {lninfo[2]}, Sim: {result}")
|
||||
mismatches += 1
|
||||
if args.dist:
|
||||
percent_loads = str(round(100*loads/totalops))
|
||||
percent_stores = str(round(100*stores/totalops))
|
||||
percent_atoms = str(round(100*atoms/totalops))
|
||||
print("This log had", percent_loads+"% loads,", percent_stores+"% stores, and", percent_atoms+"% atomic operations.")
|
||||
print(f"This log had {percent_loads}% loads, {percent_stores}% stores, and {percent_atoms}% atomic operations.")
|
||||
|
||||
if args.perf:
|
||||
ratio = round(hits/misses,3)
|
||||
@ -299,4 +302,5 @@ def main():
|
||||
return mismatches
|
||||
|
||||
if __name__ == '__main__':
|
||||
exit(main())
|
||||
args = parseArgs()
|
||||
sys.exit(main(args))
|
||||
|
60
bin/iterelf
60
bin/iterelf
@ -1,4 +1,4 @@
|
||||
#!/usr/bin/python3
|
||||
#!/usr/bin/env python3
|
||||
|
||||
# iterelf
|
||||
# David_Harris@hmc.edu and Rose Thompson 7/3/2024
|
||||
@ -7,20 +7,21 @@
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import sys
|
||||
import multiprocessing
|
||||
from multiprocessing import Pool, TimeoutError
|
||||
from multiprocessing import Pool, TimeoutError as MPTimeoutError
|
||||
TIMEOUT_DUR = 60 # 1` minute
|
||||
|
||||
class bcolors:
|
||||
HEADER = '\033[95m'
|
||||
OKBLUE = '\033[94m'
|
||||
OKCYAN = '\033[96m'
|
||||
OKGREEN = '\033[92m'
|
||||
WARNING = '\033[93m'
|
||||
FAIL = '\033[91m'
|
||||
ENDC = '\033[0m'
|
||||
BOLD = '\033[1m'
|
||||
UNDERLINE = '\033[4m'
|
||||
HEADER = "\033[95m"
|
||||
OKBLUE = "\033[94m"
|
||||
OKCYAN = "\033[96m"
|
||||
OKGREEN = "\033[92m"
|
||||
WARNING = "\033[93m"
|
||||
FAIL = "\033[91m"
|
||||
ENDC = "\033[0m"
|
||||
BOLD = "\033[1m"
|
||||
UNDERLINE = "\033[4m"
|
||||
|
||||
def search_log_for_mismatches(logfile):
|
||||
"""Search through the given log file for text, returning True if it is found or False if it is not"""
|
||||
@ -28,15 +29,14 @@ def search_log_for_mismatches(logfile):
|
||||
os.system(grepwarn)
|
||||
greperr = "grep -H Error: " + logfile
|
||||
os.system(greperr)
|
||||
grepcmd = "grep -a -e 'Mismatches : 0' '%s' > /dev/null" % logfile
|
||||
# print(" search_log_for_text invoking %s" % grepcmd)
|
||||
grepcmd = f"grep -a -e 'Mismatches : 0' '{logfile}' > /dev/null"
|
||||
return os.system(grepcmd) == 0
|
||||
|
||||
def run_test_case(elf):
|
||||
"""Run the given test case, and return 0 if the test suceeds and 1 if it fails"""
|
||||
WALLY = os.environ.get('WALLY')
|
||||
fields = elf.rsplit('/', 3)
|
||||
if (fields[2] == "ref"):
|
||||
WALLY = os.environ.get("WALLY")
|
||||
fields = elf.rsplit("/", 3)
|
||||
if fields[2] == "ref":
|
||||
shortelf = fields[1] + "_" + fields[3]
|
||||
else:
|
||||
shortelf = fields[2] + "_" + fields[3]
|
||||
@ -46,15 +46,15 @@ def run_test_case(elf):
|
||||
# print("cmd = " + cmd)
|
||||
os.system(cmd)
|
||||
if search_log_for_mismatches(logfile):
|
||||
print(f"{bcolors.OKGREEN}%s: Success{bcolors.ENDC}" % (cmd))
|
||||
print(f"{bcolors.OKGREEN}{cmd}: Success{bcolors.ENDC}")
|
||||
return 0
|
||||
elif("WALLY-cbom-01" in elf):
|
||||
elif "WALLY-cbom-01" in elf:
|
||||
# Remove this when CBO instructions are modeled in ImperasDV
|
||||
print(f"{bcolors.OKCYAN}%s: Expected mismatch because ImperasDV does not yet model cache for CBO instructions {bcolors.ENDC}" % (cmd))
|
||||
print(f"{bcolors.OKCYAN}{cmd}: Expected mismatch because ImperasDV does not yet model cache for CBO instructions {bcolors.ENDC}")
|
||||
return 0
|
||||
else:
|
||||
print(f"{bcolors.FAIL}%s: Failures detected in output{bcolors.ENDC}" % (cmd))
|
||||
print(" Check %s" % logfile)
|
||||
print(f"{bcolors.FAIL}{cmd}: Failures detected in output{bcolors.ENDC}")
|
||||
print(f" Check {logfile}")
|
||||
return 1
|
||||
|
||||
##################################
|
||||
@ -74,16 +74,15 @@ args = parser.parse_args()
|
||||
# find all ELF files in directory
|
||||
|
||||
ElfList = []
|
||||
if (os.path.isdir(args.dir)):
|
||||
if os.path.isdir(args.dir):
|
||||
DirectorMode = 1
|
||||
for dirpath, dirnames, filenames in os.walk(os.path.abspath(args.dir)):
|
||||
for file in filenames:
|
||||
if (file.endswith("elf") and not file.endswith(args.exclude)):
|
||||
if file.endswith("elf") and not file.endswith(args.exclude):
|
||||
ElfList.append(os.path.join(dirpath, file))
|
||||
else:
|
||||
print(args.dir + " is not a directory")
|
||||
exit(1)
|
||||
#print(ElfList)
|
||||
sys.exit(1)
|
||||
|
||||
# spawn parallel wsim jobs for each ELF file
|
||||
|
||||
@ -93,15 +92,14 @@ with Pool(processes=min(len(ElfList),multiprocessing.cpu_count(), ImperasDVLicen
|
||||
results = {}
|
||||
for elf in ElfList:
|
||||
results[elf] = pool.apply_async(run_test_case, (elf,))
|
||||
for (elf,result) in results.items():
|
||||
for elf, result in results.items():
|
||||
try:
|
||||
num_fail += result.get(timeout=TIMEOUT_DUR)
|
||||
except TimeoutError:
|
||||
except MPTimeoutError:
|
||||
num_fail += 1
|
||||
print(f"{bcolors.FAIL}%s: Timeout - runtime exceeded %d seconds{bcolors.ENDC}" % (elf, TIMEOUT_DUR))
|
||||
print(f"{bcolors.FAIL}{elf}: Timeout - runtime exceeded {TIMEOUT_DUR} seconds{bcolors.ENDC}")
|
||||
|
||||
if (num_fail == 0):
|
||||
if num_fail == 0:
|
||||
print(f"{bcolors.OKGREEN}SUCCESS! All tests ran without failures{bcolors.ENDC}")
|
||||
else:
|
||||
print(f"{bcolors.FAIL}Completed %d tests with %d failures{bcolors.ENDC}" % (len(ElfList), num_fail))
|
||||
|
||||
print(f"{bcolors.FAIL}Completed {len(ElfList)} tests with {num_fail} failures{bcolors.ENDC}")
|
||||
|
@ -68,7 +68,7 @@ In summary, this Python script facilitates the automation of nightly regression
|
||||
|
||||
import os
|
||||
import shutil
|
||||
from datetime import datetime, timedelta
|
||||
from datetime import datetime
|
||||
import time
|
||||
import re
|
||||
import markdown
|
||||
@ -78,9 +78,6 @@ import logging
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class FolderManager:
|
||||
"""A class for managing folders and repository cloning."""
|
||||
|
||||
@ -115,9 +112,6 @@ class FolderManager:
|
||||
"""
|
||||
|
||||
for folder in folders:
|
||||
folder_path = os.path.join(self.base_parent_dir, folder)
|
||||
# if not os.path.exists(folder_path):
|
||||
# os.makedirs(folder_path)
|
||||
if not os.path.exists(folder):
|
||||
os.makedirs(folder)
|
||||
|
||||
@ -171,7 +165,6 @@ class FolderManager:
|
||||
Returns:
|
||||
None
|
||||
"""
|
||||
todays_date = datetime.now().strftime("%Y-%m-%d")
|
||||
cvw = folder.joinpath("cvw")
|
||||
tmp_folder = os.path.join(cvw, "tmp") # temprorary files will be stored in here
|
||||
if not cvw.exists():
|
||||
@ -287,7 +280,7 @@ class TestRunner:
|
||||
|
||||
if target:
|
||||
output_file = self.log_dir.joinpath(f"make-{target}-output.log")
|
||||
else: output_file = self.log_dir.joinpath(f"make-output.log")
|
||||
else: output_file = self.log_dir.joinpath("make-output.log")
|
||||
|
||||
# Source setup script and execute make with target and cores/2
|
||||
if target:
|
||||
@ -398,7 +391,7 @@ class TestRunner:
|
||||
# Implement cleaning and formatting logic here
|
||||
|
||||
# Open up the file with only read permissions
|
||||
with open(input_file, 'r') as input_file:
|
||||
with open(input_file) as input_file:
|
||||
uncleaned_output = input_file.read()
|
||||
|
||||
# use something like this function to detect pass and fail
|
||||
@ -461,7 +454,6 @@ class TestRunner:
|
||||
None
|
||||
"""
|
||||
# Implement markdown rewriting logic here
|
||||
timestamp = datetime.now().strftime("%Y-%m-%d")
|
||||
|
||||
# output_directory = self.base_parent_dir.joinpath("results")
|
||||
os.chdir(self.results_dir)
|
||||
@ -481,15 +473,15 @@ class TestRunner:
|
||||
if failed_configs:
|
||||
md_file.write("## Failed Configurations\n\n")
|
||||
for config, log_file in failed_configs:
|
||||
md_file.write(f"- <span class=\"failure\" style=\"color: red;\">{config}</span> ({log_file})\n")
|
||||
md_file.write(f'- <span class="failure" style="color: red;">{config}</span> ({log_file})\n')
|
||||
md_file.write("\n")
|
||||
else:
|
||||
md_file.write("## Failed Configurations\n")
|
||||
md_file.write(f"No Failures\n")
|
||||
md_file.write("No Failures\n")
|
||||
|
||||
md_file.write("\n## Passed Configurations\n")
|
||||
for config in passed_configs:
|
||||
md_file.write(f"- <span class=\"success\" style=\"color: green;\">{config}</span>\n")
|
||||
md_file.write(f'- <span class="success" style="color: green;">{config}</span>\n')
|
||||
|
||||
self.logger.info("writing test outputs to markdown")
|
||||
|
||||
@ -534,7 +526,7 @@ class TestRunner:
|
||||
md_file.write("\n")
|
||||
except subprocess.CalledProcessError as e:
|
||||
# Handle if the command fails
|
||||
md_file.write(f"Failed to identify host and Operating System information: {str(e)}")
|
||||
md_file.write(f"Failed to identify host and Operating System information: {e!s}")
|
||||
|
||||
# Which tests did we run
|
||||
md_file.write(f"\n**Tests made:** `make {test_type}`\n")
|
||||
@ -545,18 +537,18 @@ class TestRunner:
|
||||
md_file.write(f"**Total Failures: {total_number_failures}**\n")
|
||||
|
||||
# Failed Tests
|
||||
md_file.write(f"\n\n## Failed Tests")
|
||||
md_file.write("\n\n## Failed Tests")
|
||||
md_file.write(f"\n**Total failed tests: {total_number_failures}**")
|
||||
for (test_item, item) in zip(test_list, failed_tests):
|
||||
md_file.write(f"\n\n### {test_item[1]} test")
|
||||
md_file.write(f"\n**Command used:** {test_item[0]} {test_item[1]} {' '.join(test_item[2])}\n\n")
|
||||
md_file.write(f"**Failed Tests:**\n")
|
||||
md_file.write("**Failed Tests:**\n")
|
||||
|
||||
|
||||
|
||||
if len(item) == 0:
|
||||
md_file.write("\n")
|
||||
md_file.write(f"* <span class=\"no-failure\" style=\"color: green;\">No failures</span>\n")
|
||||
md_file.write('* <span class="no-failure" style="color: green;">No failures</span>\n')
|
||||
md_file.write("\n")
|
||||
else:
|
||||
for failed_test in item:
|
||||
@ -564,29 +556,29 @@ class TestRunner:
|
||||
log_file = failed_test[1]
|
||||
|
||||
md_file.write("\n")
|
||||
md_file.write(f"* <span class=\"failure\" style=\"color: red;\">{config}</span> ({log_file})\n")
|
||||
md_file.write(f'* <span class="failure" style="color: red;">{config}</span> ({log_file})\n')
|
||||
md_file.write("\n")
|
||||
# Successful Tests
|
||||
|
||||
md_file.write(f"\n\n## Successful Tests")
|
||||
md_file.write("\n\n## Successful Tests")
|
||||
md_file.write(f"\n**Total successful tests: {total_number_success}**")
|
||||
for (test_item, item) in zip(test_list, passed_tests):
|
||||
md_file.write(f"\n\n### {test_item[1]} test")
|
||||
md_file.write(f"\n**Command used:** {test_item[0]} {test_item[1]} {' '.join(test_item[2])}\n\n")
|
||||
md_file.write(f"\n**Successful Tests:**\n")
|
||||
md_file.write("\n**Successful Tests:**\n")
|
||||
|
||||
|
||||
|
||||
if len(item) == 0:
|
||||
md_file.write("\n")
|
||||
md_file.write(f"* <span class=\"no-successes\" style=\"color: red;\">No successes</span>\n")
|
||||
md_file.write('* <span class="no-successes" style="color: red;">No successes</span>\n')
|
||||
md_file.write("\n")
|
||||
else:
|
||||
for passed_tests in item:
|
||||
config = passed_tests
|
||||
|
||||
md_file.write("\n")
|
||||
md_file.write(f"* <span class=\"success\" style=\"color: green;\">{config}</span>\n")
|
||||
md_file.write(f'* <span class="success" style="color: green;">{config}</span>\n')
|
||||
md_file.write("\n")
|
||||
|
||||
self.logger.info("Combining markdown files")
|
||||
@ -606,7 +598,7 @@ class TestRunner:
|
||||
# Implement markdown to HTML conversion logic here
|
||||
os.chdir(self.results_dir)
|
||||
|
||||
with open(markdown_file, 'r') as md_file:
|
||||
with open(markdown_file) as md_file:
|
||||
md_content = md_file.read()
|
||||
html_content = markdown.markdown(md_content)
|
||||
|
||||
@ -640,7 +632,7 @@ class TestRunner:
|
||||
os.chdir(self.results_dir)
|
||||
html_file = "results.html"
|
||||
|
||||
with open(html_file, 'r') as html_file:
|
||||
with open(html_file) as html_file:
|
||||
body = html_file.read()
|
||||
|
||||
try:
|
||||
@ -688,13 +680,10 @@ def main():
|
||||
|
||||
# file paths for where the results and repos will be saved: repos and results can be changed to whatever
|
||||
today = datetime.now().strftime("%Y-%m-%d")
|
||||
yesterday_dt = datetime.now() - timedelta(days=1)
|
||||
yesterday = yesterday_dt.strftime("%Y-%m-%d")
|
||||
cvw_path = Path.home().joinpath(args.path, today)
|
||||
results_path = Path.home().joinpath(args.path, today, "results")
|
||||
log_path = Path.home().joinpath(args.path, today, "logs")
|
||||
log_file_path = log_path.joinpath("nightly_build.log")
|
||||
previous_cvw_path = Path.home().joinpath(args.path,f"{yesterday}/cvw")
|
||||
# creates the object
|
||||
folder_manager = FolderManager(basedir=args.path)
|
||||
|
||||
@ -765,12 +754,6 @@ def main():
|
||||
|
||||
if args.target != "no":
|
||||
test_runner.execute_makefile(target = args.target, makefile_path=test_runner.cvw)
|
||||
# TODO: remove vestigial code if no longer wanted
|
||||
# if args.target == "all":
|
||||
# # Compile Linux for local testing
|
||||
# test_runner.set_env_var("RISCV",str(test_runner.cvw))
|
||||
# linux_path = test_runner.cvw / "linux"
|
||||
# test_runner.execute_makefile(target = "all", makefile_path=linux_path)
|
||||
|
||||
#############################################
|
||||
# RUN TESTS #
|
||||
@ -817,7 +800,7 @@ def main():
|
||||
logger.info(f"The total failures for all tests ran are: {total_number_failures}")
|
||||
|
||||
# Copy actual test logs from sim/questa, sim/verilator, sim/vcs
|
||||
if not args.tests == "test_lint":
|
||||
if args.tests != 'test_lint':
|
||||
test_runner.copy_sim_logs([test_runner.cvw / "sim/questa/logs", test_runner.cvw / "sim/verilator/logs", test_runner.cvw / "sim/vcs/logs"])
|
||||
|
||||
#############################################
|
||||
|
@ -46,7 +46,7 @@ def ParseBranchListFile(path):
|
||||
is formated in row columns. Each row is a trace with the file, branch predictor type, and the parameters.
|
||||
parameters can be any number and depend on the predictor type. Returns a list of lists.'''
|
||||
lst = []
|
||||
BranchList = open(path, 'r')
|
||||
with open(path) as BranchList:
|
||||
for line in BranchList:
|
||||
tokens = line.split()
|
||||
predictorLog = os.path.dirname(path) + '/' + tokens[0]
|
||||
@ -62,9 +62,9 @@ def ProcessFile(fileName):
|
||||
# 1 find lines with Read memfile and extract test name
|
||||
# 2 parse counters into a list of (name, value) tuples (dictionary maybe?)
|
||||
benchmarks = []
|
||||
transcript = open(fileName, 'r')
|
||||
HPMClist = { }
|
||||
testName = ''
|
||||
with open(fileName) as transcript:
|
||||
for line in transcript.readlines():
|
||||
lineToken = line.split()
|
||||
if(len(lineToken) > 3 and lineToken[1] == 'Read' and lineToken[2] == 'memfile'):
|
||||
@ -227,13 +227,13 @@ def ReportAsTable(benchmarkDict):
|
||||
|
||||
sys.stdout.write('benchmark\t\t')
|
||||
for name in FirstLine:
|
||||
if(len(name) < 8): sys.stdout.write('%s\t\t' % name)
|
||||
else: sys.stdout.write('%s\t' % name)
|
||||
if(len(name) < 8): sys.stdout.write(f'{name}\t\t')
|
||||
else: sys.stdout.write(f'{name}\t')
|
||||
sys.stdout.write('\n')
|
||||
sys.stdout.write('size\t\t\t')
|
||||
for size in SecondLine:
|
||||
if(len(str(size)) < 8): sys.stdout.write('%d\t\t' % size)
|
||||
else: sys.stdout.write('%d\t' % size)
|
||||
if(len(str(size)) < 8): sys.stdout.write(f'{size}\t\t')
|
||||
else: sys.stdout.write(f'{size}\t')
|
||||
sys.stdout.write('\n')
|
||||
|
||||
if(args.summary):
|
||||
@ -245,9 +245,9 @@ def ReportAsTable(benchmarkDict):
|
||||
if(not args.summary):
|
||||
for benchmark in benchmarkDict:
|
||||
length = len(benchmark)
|
||||
if(length < 8): sys.stdout.write('%s\t\t\t' % benchmark)
|
||||
elif(length < 16): sys.stdout.write('%s\t\t' % benchmark)
|
||||
else: sys.stdout.write('%s\t' % benchmark)
|
||||
if(length < 8): sys.stdout.write(f'{benchmark}\t\t\t')
|
||||
elif(length < 16): sys.stdout.write(f'{benchmark}\t\t')
|
||||
else: sys.stdout.write(f'{benchmark}\t')
|
||||
for (name, typ, entries, size, val) in benchmarkDict[benchmark]:
|
||||
sys.stdout.write('%0.2f\t\t' % (val if not args.invert else 100 -val))
|
||||
sys.stdout.write('\n')
|
||||
@ -256,14 +256,14 @@ def ReportAsText(benchmarkDict):
|
||||
if(args.summary):
|
||||
mean = benchmarkDict['Mean']
|
||||
print('Mean')
|
||||
for (name, typ, entries. size, val) in mean:
|
||||
sys.stdout.write('%s %s %0.2f\n' % (name, entries if not args.size else size, val if not args.invert else 100 - val))
|
||||
for (name, typ, entries, size, val) in mean:
|
||||
sys.stdout.write(f'{name} {entries if not args.size else size} {val if not args.invert else 100 - val:0.2f}\n')
|
||||
|
||||
if(not args.summary):
|
||||
for benchmark in benchmarkDict:
|
||||
print(benchmark)
|
||||
for (name, type, entries, size, val) in benchmarkDict[benchmark]:
|
||||
sys.stdout.write('%s %s %0.2f\n' % (name, entries if not args.size else size, val if not args.invert else 100 - val))
|
||||
sys.stdout.write(f'{name} {entries if not args.size else size} {val if not args.invert else 100 - val:0.2f}\n')
|
||||
|
||||
def Inversion(lst):
|
||||
return [x if not args.invert else 100 - x for x in lst]
|
||||
@ -275,7 +275,7 @@ def BarGraph(seriesDict, xlabelList, BenchPerRow, FileName, IncludeLegend):
|
||||
# the space between groups is 1
|
||||
EffectiveNumInGroup = NumberInGroup + 2
|
||||
barWidth = 1 / EffectiveNumInGroup
|
||||
fig = plt.subplots(figsize = (EffectiveNumInGroup*BenchPerRow/8, 4))
|
||||
_ = plt.subplots(figsize = (EffectiveNumInGroup*BenchPerRow/8, 4))
|
||||
colors = ['blue', 'blue', 'blue', 'blue', 'blue', 'blue', 'black', 'black', 'black', 'black', 'black', 'black']
|
||||
for name in seriesDict:
|
||||
values = seriesDict[name]
|
||||
@ -322,14 +322,13 @@ def ReportAsGraph(benchmarkDict, bar, FileName):
|
||||
if(args.summary):
|
||||
markers = ['x', '.', '+', '*', '^', 'o', ',', 's']
|
||||
colors = ['blue', 'black', 'gray', 'dodgerblue', 'lightsteelblue', 'turquoise', 'black', 'blue']
|
||||
temp = benchmarkDict['Mean']
|
||||
|
||||
# the benchmarkDict['Mean'] contains sequencies of results for multiple
|
||||
# branch predictors with various parameterizations
|
||||
# group the parameterizations by the common typ.
|
||||
sequencies = {}
|
||||
for (name, typ, entries, size, value) in benchmarkDict['Mean']:
|
||||
if not typ in sequencies:
|
||||
if typ not in sequencies:
|
||||
sequencies[typ] = [(entries if not args.size else int(size/8), value)]
|
||||
else:
|
||||
sequencies[typ].append((entries if not args.size else int(size/8) ,value))
|
||||
@ -354,7 +353,7 @@ def ReportAsGraph(benchmarkDict, bar, FileName):
|
||||
axes.set_xticks(xdata)
|
||||
axes.set_xticklabels(xdata)
|
||||
axes.grid(color='b', alpha=0.5, linestyle='dashed', linewidth=0.5)
|
||||
if(FileName == None): plt.show()
|
||||
if FileName is None: plt.show()
|
||||
else: plt.savefig(FileName)
|
||||
|
||||
# if(not args.summary):
|
||||
@ -378,10 +377,10 @@ def ReportAsGraph(benchmarkDict, bar, FileName):
|
||||
|
||||
if(not args.summary):
|
||||
NumBenchmarks = len(benchmarkDict)
|
||||
NumBenchmarksSqrt = math.sqrt(NumBenchmarks)
|
||||
isSquare = math.isclose(NumBenchmarksSqrt, round(NumBenchmarksSqrt))
|
||||
numCol = math.floor(NumBenchmarksSqrt)
|
||||
numRow = numCol + (0 if isSquare else 1)
|
||||
# NumBenchmarksSqrt = math.sqrt(NumBenchmarks)
|
||||
# isSquare = math.isclose(NumBenchmarksSqrt, round(NumBenchmarksSqrt))
|
||||
# numCol = math.floor(NumBenchmarksSqrt)
|
||||
# numRow = numCol + (0 if isSquare else 1)
|
||||
index = 1
|
||||
BenchPerRow = 5
|
||||
|
||||
@ -414,7 +413,7 @@ def ReportAsGraph(benchmarkDict, bar, FileName):
|
||||
# on each piece.
|
||||
for row in range(0, math.ceil(NumBenchmarks / BenchPerRow)):
|
||||
(xlabelListTrunk, seriesDictTrunk) = SelectPartition(xlabelListBig, seriesDictBig, row, BenchPerRow)
|
||||
FileName = 'barSegment%d.svg' % row
|
||||
FileName = f'barSegment{row}.svg'
|
||||
groupLen = len(xlabelListTrunk)
|
||||
BarGraph(seriesDictTrunk, xlabelListTrunk, groupLen, FileName, (row == 0))
|
||||
|
||||
|
@ -4,6 +4,7 @@
|
||||
# regression-wally
|
||||
# David_Harris@Hmc.edu 25 January 2021
|
||||
# Modified by Jarred Allen <jaallen@g.hmc.edu> and many others
|
||||
# jcarlin@hmc.edu December 2024
|
||||
# SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1
|
||||
#
|
||||
# Run a regression with multiple configurations in parallel and exit with
|
||||
@ -11,11 +12,23 @@
|
||||
# output.
|
||||
#
|
||||
##################################
|
||||
import sys,os,shutil
|
||||
import sys
|
||||
import shutil
|
||||
import os
|
||||
import argparse
|
||||
import multiprocessing
|
||||
from collections import namedtuple
|
||||
from multiprocessing import Pool, TimeoutError
|
||||
from multiprocessing import Pool, TimeoutError as MPTimeoutError
|
||||
|
||||
# Globals
|
||||
WALLY = os.environ.get('WALLY')
|
||||
regressionDir = f'{WALLY}/sim'
|
||||
archVerifDir = f'{WALLY}/addins/cvw-arch-verif'
|
||||
coveragesim = "questa" # Questa is required for code/functional coverage
|
||||
defaultsim = "verilator" # Default simulator for all other tests
|
||||
lockstepsim = "questa"
|
||||
testfloatsim = "questa" # change to Verilator when Issue #707 about testfloat not running Verilator is resolved
|
||||
|
||||
|
||||
##################################
|
||||
# Define lists of configurations and tests to run on each configuration
|
||||
@ -25,7 +38,7 @@ from multiprocessing import Pool, TimeoutError
|
||||
# The element consists of the configuration name, a list of test suites to run,
|
||||
# optionally a string to pass to the simulator, and optionally a nonstandard grep string to check for success
|
||||
|
||||
tests = [
|
||||
standard_tests = [
|
||||
["rv32e", ["arch32e"]],
|
||||
["rv32i", ["arch32i"]],
|
||||
["rv32imc", ["arch32i", "arch32c", "arch32m", "wally32periph"]],
|
||||
@ -34,42 +47,31 @@ tests = [
|
||||
"arch32zba", "arch32zbb", "arch32zbc", "arch32zbs", "arch32zfh", "arch32zfh_fma",
|
||||
"arch32zfh_divsqrt", "arch32zfaf", "arch32zfad", "wally32a_lrsc", "wally32priv", "wally32periph", "arch32zcb",
|
||||
"arch32zbkb", "arch32zbkc", "arch32zbkx", "arch32zknd", "arch32zkne", "arch32zknh", "arch32vm_sv32", "arch32pmp"]],
|
||||
["rv64i", ["arch64i"]]
|
||||
["rv64i", ["arch64i"]],
|
||||
["rv64gc", ["arch64f", "arch64d", "arch64zfh", "arch64f_fma", "arch64d_fma", "arch64zfh_fma", "arch64f_divsqrt",
|
||||
"arch64d_divsqrt", "arch64zfh_divsqrt", "arch64zfaf", "arch64zfad", "coverage64gc", "arch64i", "arch64priv",
|
||||
"arch64c", "arch64m", "arch64zcb", "arch64zifencei", "arch64zicond", "arch64a_amo", "wally64a_lrsc",
|
||||
"wally64periph", "wally64priv", "arch64zbkb", "arch64zbkc", "arch64zbkx", "arch64zknd", "arch64zkne", "arch64zknh",
|
||||
"arch64zba", "arch64zbb", "arch64zbc", "arch64zbs", "arch64pmp"]], # add when working: "arch64zicboz"
|
||||
]
|
||||
|
||||
# Separate test for short buildroot run through OpenSBI UART output
|
||||
tests_buildrootshort = [
|
||||
["buildroot", ["buildroot"], [f"+INSTR_LIMIT=1400000"], # Instruction limit gets to first OpenSBI UART output
|
||||
["buildroot", ["buildroot"], "--args +INSTR_LIMIT=1400000", # Instruction limit gets to first OpenSBI UART output
|
||||
"OpenSBI v", "buildroot_uart.out"]
|
||||
]
|
||||
|
||||
# Separate test for full buildroot run
|
||||
tests_buildrootboot = [
|
||||
["buildroot", ["buildroot"], [f"+INSTR_LIMIT=600000000"], # boot entire buildroot Linux to login prompt
|
||||
["buildroot", ["buildroot"], "--args +INSTR_LIMIT=600000000", # boot entire buildroot Linux to login prompt
|
||||
"WallyHostname login: ", "buildroot_uart.out"]
|
||||
]
|
||||
|
||||
tests_buildrootbootlockstep = [
|
||||
["buildroot", ["buildroot"], [f"+INSTR_LIMIT=600000000 --lockstep"], # boot entire buildroot Linux to login prompt
|
||||
["buildroot", ["buildroot"], "--args +INSTR_LIMIT=600000000 --lockstep", # boot entire buildroot Linux to login prompt
|
||||
"WallyHostname login: ", "buildroot_uart.out"]
|
||||
]
|
||||
|
||||
|
||||
# Separate out floating-point tests for RV64 to speed up coverage
|
||||
tests64gc_nofp = [
|
||||
["rv64gc", ["coverage64gc", "arch64i", "arch64priv", "arch64c", "arch64m", "arch64zcb",
|
||||
"arch64zifencei", "arch64zicond", "arch64a_amo", "wally64a_lrsc", "wally64periph", "wally64priv",
|
||||
"arch64zbkb", "arch64zbkc", "arch64zbkx", "arch64zknd", "arch64zkne", "arch64zknh",
|
||||
"arch64zba", "arch64zbb", "arch64zbc", "arch64zbs", "arch64pmp"]] # add when working: "arch64zicboz"
|
||||
]
|
||||
|
||||
tests64gc_fp = [
|
||||
["rv64gc", ["arch64f", "arch64d", "arch64zfh",
|
||||
"arch64f_fma", "arch64d_fma", "arch64zfh_fma",
|
||||
"arch64f_divsqrt", "arch64d_divsqrt", "arch64zfh_divsqrt",
|
||||
"arch64zfaf", "arch64zfad"]]
|
||||
]
|
||||
|
||||
derivconfigtests = [
|
||||
# memory system
|
||||
["tlb2_rv32gc", ["wally32priv"]],
|
||||
@ -181,7 +183,6 @@ derivconfigtests = [
|
||||
]
|
||||
|
||||
bpredtests = [
|
||||
|
||||
["nobpred_rv32gc", ["rv32i"]],
|
||||
["bpred_TWOBIT_6_16_10_0_rv32gc", ["embench"], "-GPrintHPMCounters=1"],
|
||||
["bpred_TWOBIT_8_16_10_0_rv32gc", ["embench"], "-GPrintHPMCounters=1"],
|
||||
@ -230,6 +231,33 @@ bpredtests = [
|
||||
["bpred_GSHARE_10_10_10_1_rv32gc", ["embench"], "-GPrintHPMCounters=1"]
|
||||
]
|
||||
|
||||
testfloatdivconfigs = [
|
||||
"fdh_div_2_1_rv32gc", "fdh_div_2_1_rv64gc", "fdh_div_2_2_rv32gc",
|
||||
"fdh_div_2_2_rv64gc", "fdh_div_2_4_rv32gc", "fdh_div_2_4_rv64gc",
|
||||
"fdh_div_4_1_rv32gc", "fdh_div_4_1_rv64gc", "fdh_div_4_2_rv32gc",
|
||||
"fdh_div_4_2_rv64gc", "fdh_div_4_4_rv32gc", "fdh_div_4_4_rv64gc",
|
||||
"fd_div_2_1_rv32gc", "fd_div_2_1_rv64gc", "fd_div_2_2_rv32gc",
|
||||
"fd_div_2_2_rv64gc", "fd_div_2_4_rv32gc", "fd_div_2_4_rv64gc",
|
||||
"fd_div_4_1_rv32gc", "fd_div_4_1_rv64gc", "fd_div_4_2_rv32gc",
|
||||
"fd_div_4_2_rv64gc", "fd_div_4_4_rv32gc", "fd_div_4_4_rv64gc",
|
||||
"fdqh_div_2_1_rv32gc", "fdqh_div_2_1_rv64gc", "fdqh_div_2_2_rv32gc",
|
||||
"fdqh_div_2_2_rv64gc", "fdqh_div_2_4_rv32gc", "fdqh_div_2_4_rv64gc",
|
||||
"fdqh_div_4_1_rv32gc", "fdqh_div_4_1_rv64gc", "fdqh_div_4_2_rv32gc",
|
||||
"fdqh_div_4_2_rv64gc", "fdqh_div_4_4_rv32gc", "fdqh_div_4_4_rv64gc",
|
||||
"fdq_div_2_1_rv32gc", "fdq_div_2_1_rv64gc", "fdq_div_2_2_rv32gc",
|
||||
"fdq_div_2_2_rv64gc", "fdq_div_2_4_rv32gc", "fdq_div_2_4_rv64gc",
|
||||
"fdq_div_4_1_rv32gc", "fdq_div_4_1_rv64gc", "fdq_div_4_2_rv32gc",
|
||||
"fdq_div_4_2_rv64gc", "fdq_div_4_4_rv32gc", "fdq_div_4_4_rv64gc",
|
||||
"fh_div_2_1_rv32gc", "fh_div_2_1_rv64gc", "fh_div_2_2_rv32gc",
|
||||
"fh_div_2_2_rv64gc", "fh_div_2_4_rv32gc", "fh_div_2_4_rv64gc",
|
||||
"fh_div_4_1_rv32gc", "fh_div_4_1_rv64gc", "fh_div_4_2_rv32gc",
|
||||
"fh_div_4_2_rv64gc", "fh_div_4_4_rv32gc", "fh_div_4_4_rv64gc",
|
||||
"f_div_2_1_rv32gc", "f_div_2_1_rv64gc", "f_div_2_2_rv32gc",
|
||||
"f_div_2_2_rv64gc", "f_div_2_4_rv32gc", "f_div_2_4_rv64gc",
|
||||
"f_div_4_1_rv32gc", "f_div_4_1_rv64gc", "f_div_4_2_rv32gc",
|
||||
"f_div_4_2_rv64gc", "f_div_4_4_rv32gc", "f_div_4_4_rv64gc"
|
||||
]
|
||||
|
||||
# list of tests not supported by ImperasDV yet that should be waived during lockstep testing
|
||||
lockstepwaivers = [
|
||||
"WALLY-q-01.S_ref.elf", # Q extension is not supported by ImperasDV
|
||||
@ -261,109 +289,76 @@ class bcolors:
|
||||
BOLD = '\033[1m'
|
||||
UNDERLINE = '\033[4m'
|
||||
|
||||
def addTests(tests, sim):
|
||||
sim_logdir = WALLY+ "/sim/" + sim + "/logs/"
|
||||
for test in tests:
|
||||
|
||||
def addTests(testList, sim, coverStr, configs):
|
||||
sim_logdir = f"{regressionDir}/{sim}/logs/"
|
||||
for test in testList:
|
||||
config = test[0]
|
||||
suites = test[1]
|
||||
if (len(test) >= 3):
|
||||
args = " --args " + " ".join(test[2])
|
||||
else:
|
||||
args = ""
|
||||
if (len(test) >= 4):
|
||||
gs = test[3]
|
||||
else:
|
||||
gs = "All tests ran without failures"
|
||||
cmdPrefix="wsim --sim " + sim + " " + coverStr + " " + config
|
||||
flags = f"{test[2]}" if len(test) >= 3 else ""
|
||||
gs = test[3] if len(test) >= 4 else "All tests ran without failures"
|
||||
cmdPrefix=f"wsim --sim {sim} {coverStr} {flags} {config}"
|
||||
for t in suites:
|
||||
sim_log = sim_logdir + config + "_" + t + ".log"
|
||||
if (len(test) >= 5):
|
||||
grepfile = sim_logdir + test[4]
|
||||
else:
|
||||
grepfile = sim_log
|
||||
sim_log = f"{sim_logdir}{config}_{t}.log"
|
||||
grepfile = sim_logdir + test[4] if len(test) >= 5 else sim_log
|
||||
tc = TestCase(
|
||||
name=t,
|
||||
variant=config,
|
||||
cmd=cmdPrefix + " " + t + args + " > " + sim_log,
|
||||
cmd=f"{cmdPrefix} {t} > {sim_log}",
|
||||
grepstr=gs,
|
||||
grepfile = grepfile)
|
||||
configs.append(tc)
|
||||
|
||||
|
||||
def addTestsByDir(dir, config, sim, lockstepMode=0, brekerMode=0):
|
||||
if os.path.isdir(dir):
|
||||
sim_logdir = WALLY+ "/sim/" + sim + "/logs/"
|
||||
if coverStr == "--fcov": # use --fcov in place of --lockstep
|
||||
cmdPrefix="wsim --sim " + sim + " " + coverStr + " " + config
|
||||
def addTestsByDir(testDir, config, sim, coverStr, configs, lockstepMode=0, brekerMode=0):
|
||||
if not os.path.isdir(testDir):
|
||||
print(f"Error: Directory not found: {testDir}")
|
||||
sys.exit(1)
|
||||
|
||||
sim_logdir = f"{regressionDir}/{sim}/logs/"
|
||||
cmdPrefix = f"wsim --sim {sim} {coverStr} {'--lockstep' if lockstepMode else ''} {config}"
|
||||
# fcov/ccov only runs on WALLY-COV-ALL.elf files; other lockstep runs on all files
|
||||
fileEnd = "ALL.elf" if "cvw-arch-verif/tests" in testDir and "priv" not in testDir and (coverStr == "--fcov" or coverStr == "--ccov") else ".elf"
|
||||
if lockstepMode or coverStr == "--fcov":
|
||||
gs = "Mismatches : 0"
|
||||
if ("cvw-arch-verif/tests" in dir and not "priv" in dir):
|
||||
fileEnd = "ALL.elf"
|
||||
else:
|
||||
fileEnd = ".elf"
|
||||
elif coverStr == "--ccov":
|
||||
cmdPrefix="wsim --sim " + sim + " " + coverStr + " " + config
|
||||
gs="Single Elf file tests are not signatured verified."
|
||||
if ("cvw-arch-verif/tests" in dir and not "priv" in dir):
|
||||
fileEnd = "ALL.elf"
|
||||
else:
|
||||
fileEnd = ".elf"
|
||||
elif lockstepMode:
|
||||
cmdPrefix="wsim --lockstep --sim " + sim + " " + config
|
||||
gs="Mismatches : 0"
|
||||
fileEnd = ".elf"
|
||||
elif brekerMode:
|
||||
cmdPrefix="wsim --sim " + sim + " " + config
|
||||
gs="# trek: info: summary: Test PASSED"
|
||||
fileEnd = ".elf"
|
||||
else:
|
||||
cmdPrefix="wsim --sim " + sim + " " + config
|
||||
gs = "Single Elf file tests are not signatured verified."
|
||||
fileEnd = ".elf"
|
||||
for dirpath, dirnames, filenames in os.walk(os.path.abspath(dir)):
|
||||
for dirpath, _, filenames in os.walk(os.path.abspath(testDir)):
|
||||
for file in filenames:
|
||||
# fcov lockstep only runs on WALLY-COV-ALL.elf files; other lockstep runs on all files
|
||||
if file.endswith(fileEnd):
|
||||
fullfile = os.path.join(dirpath, file)
|
||||
fields = fullfile.rsplit('/', 3)
|
||||
if (fields[2] == "ref"):
|
||||
shortelf = fields[1] + "_" + fields[3]
|
||||
if fields[2] == "ref":
|
||||
shortelf = f"{fields[1]}_{fields[3]}"
|
||||
else:
|
||||
shortelf = fields[2] + "_" + fields[3]
|
||||
if (shortelf in lockstepwaivers): # skip tests that itch bugs in ImperasDV
|
||||
shortelf = f"{fields[2]}_{fields[3]}"
|
||||
if shortelf in lockstepwaivers: # skip tests that itch bugs in ImperasDV
|
||||
print(f"{bcolors.WARNING}Skipping waived test {shortelf}{bcolors.ENDC}")
|
||||
continue
|
||||
sim_log = sim_logdir + config + "_" + shortelf + ".log"
|
||||
grepstring = ""
|
||||
sim_log = f"{sim_logdir}{config}_{shortelf}.log"
|
||||
tc = TestCase(
|
||||
name=file,
|
||||
variant=config,
|
||||
cmd=cmdPrefix + " " + fullfile + " > " + sim_log,
|
||||
cmd=f"{cmdPrefix} {fullfile} > {sim_log}",
|
||||
grepstr=gs,
|
||||
grepfile = sim_log)
|
||||
configs.append(tc)
|
||||
else:
|
||||
print("Error: Directory not found: " + dir)
|
||||
exit(1)
|
||||
|
||||
def search_log_for_text(text, grepfile):
|
||||
"""Search through the given log file for text, returning True if it is found or False if it is not"""
|
||||
grepwarn = "grep -i -H Warning: " + grepfile
|
||||
os.system(grepwarn)
|
||||
greperr = "grep -i -H Error: " + grepfile
|
||||
os.system(greperr)
|
||||
grepcmd = "grep -a -e '%s' '%s' > /dev/null" % (text, grepfile)
|
||||
# print(" search_log_for_text invoking %s" % grepcmd)
|
||||
return os.system(grepcmd) == 0
|
||||
with open(grepfile, errors="ignore") as file:
|
||||
content = file.readlines()
|
||||
for line in content:
|
||||
if "warning:" in line.lower():
|
||||
print(f"{bcolors.WARNING}{line.strip()}{bcolors.ENDC}")
|
||||
if "error:" in line.lower():
|
||||
print(f"{bcolors.FAIL}{line.strip()}{bcolors.ENDC}")
|
||||
return any(text in line for line in content)
|
||||
|
||||
def run_test_case(config, dryrun: bool = False):
|
||||
"""
|
||||
Run the given test case, and return 0 if the test suceeds and 1 if it fails
|
||||
|
||||
Do not execute commands if dryrun
|
||||
"""
|
||||
grepfile = config.grepfile
|
||||
cmd = config.cmd
|
||||
os.chdir(regressionDir)
|
||||
if dryrun:
|
||||
print(f"Executing {cmd}", flush=True)
|
||||
return 0
|
||||
@ -371,28 +366,15 @@ def run_test_case(config, dryrun: bool = False):
|
||||
os.system(cmd)
|
||||
if search_log_for_text(config.grepstr, grepfile):
|
||||
# Flush is needed to flush output to stdout when running in multiprocessing Pool
|
||||
# print(f"{bcolors.OKGREEN}%s_%s: Success{bcolors.ENDC}" % (config.variant, config.name), flush=True)
|
||||
print(f"{bcolors.OKGREEN}%s: Success{bcolors.ENDC}" % (config.cmd), flush=True)
|
||||
print(f"{bcolors.OKGREEN}{cmd}: Success{bcolors.ENDC}", flush=True)
|
||||
return 0
|
||||
else:
|
||||
print(f"{bcolors.FAIL}%s: Failures detected in output{bcolors.ENDC}" % (config.cmd), flush=True)
|
||||
print(" Check %s" % grepfile)
|
||||
print(f"{bcolors.FAIL}{cmd}: Failures detected in output{bcolors.ENDC}", flush=True)
|
||||
print(f" Check {grepfile}", flush=True)
|
||||
return 1
|
||||
|
||||
##################################
|
||||
# Main body
|
||||
##################################
|
||||
|
||||
|
||||
WALLY = os.environ.get('WALLY')
|
||||
regressionDir = WALLY + '/sim'
|
||||
os.chdir(regressionDir)
|
||||
|
||||
coveragesim = "questa" # Questa is required for code/functional coverage
|
||||
#defaultsim = "questa" # Default simulator for all other tests; change to Verilator when flow is ready
|
||||
defaultsim = "verilator" # Default simulator for all other tests
|
||||
lockstepsim = "questa"
|
||||
|
||||
def parse_args():
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("--ccov", help="Code Coverage", action="store_true")
|
||||
parser.add_argument("--fcov", help="Functional Coverage", action="store_true")
|
||||
@ -402,163 +384,112 @@ parser.add_argument("--testfloat", help="Include Testfloat floating-point unit t
|
||||
parser.add_argument("--fp", help="Include floating-point tests in coverage (slower runtime)", action="store_true") # Currently not used
|
||||
parser.add_argument("--breker", help="Run Breker tests", action="store_true") # Requires a license for the breker tool. See tests/breker/README.md for details
|
||||
parser.add_argument("--dryrun", help="Print commands invoked to console without running regression", action="store_true")
|
||||
args = parser.parse_args()
|
||||
return parser.parse_args()
|
||||
|
||||
if (args.nightly):
|
||||
nightMode = "--nightly"
|
||||
sims = ["questa", "verilator", "vcs"] # exercise all simulators; can omit a sim if no license is available
|
||||
|
||||
def process_args(args):
|
||||
coverStr = ""
|
||||
# exercise all simulators in nightly; can omit a sim if no license is available
|
||||
sims = ["questa", "verilator", "vcs"] if args.nightly else [defaultsim]
|
||||
if args.ccov:
|
||||
coverStr = "--ccov"
|
||||
TIMEOUT_DUR = 20*60 # seconds
|
||||
for d in ["ucdb", "cov"]:
|
||||
shutil.rmtree(f"{regressionDir}/questa/{d}", ignore_errors=True)
|
||||
os.makedirs(f"{regressionDir}/questa/{d}", exist_ok=True)
|
||||
elif args.fcov:
|
||||
coverStr = "--fcov"
|
||||
TIMEOUT_DUR = 8*60
|
||||
shutil.rmtree(f"{regressionDir}/questa/fcov_ucdb", ignore_errors=True)
|
||||
os.makedirs(f"{regressionDir}/questa/fcov_ucdb", exist_ok=True)
|
||||
elif args.buildroot:
|
||||
TIMEOUT_DUR = 60*1440 # 1 day
|
||||
elif args.testfloat or args.nightly:
|
||||
TIMEOUT_DUR = 30*60 # seconds
|
||||
else:
|
||||
nightMode = ""
|
||||
sims = [defaultsim]
|
||||
TIMEOUT_DUR = 10*60 # seconds
|
||||
|
||||
if (args.ccov): # only run RV64GC tests in coverage mode
|
||||
coverStr = '--ccov'
|
||||
elif (args.fcov): # only run RV64GC tests in lockstep in coverage mode
|
||||
coverStr = '--fcov'
|
||||
else:
|
||||
coverStr = ''
|
||||
return sims, coverStr, TIMEOUT_DUR
|
||||
|
||||
|
||||
def selectTests(args, sims, coverStr):
|
||||
# Run Lint
|
||||
configs = [
|
||||
TestCase(
|
||||
name="lints",
|
||||
variant="all",
|
||||
cmd="lint-wally " + nightMode + " | tee " + WALLY + "/sim/verilator/logs/all_lints.log",
|
||||
cmd=f"lint-wally {'--nightly' if args.nightly else ''} | tee {regressionDir}/verilator/logs/all_lints.log",
|
||||
grepstr="lints run with no errors or warnings",
|
||||
grepfile = WALLY + "/sim/verilator/logs/all_lints.log")
|
||||
grepfile = f"{regressionDir}/verilator/logs/all_lints.log")
|
||||
]
|
||||
|
||||
|
||||
|
||||
# run full buildroot boot simulation (slow) if buildroot flag is set. Start it early to overlap with other tests
|
||||
if (args.buildroot):
|
||||
if args.buildroot:
|
||||
# addTests(tests_buildrootboot, defaultsim) # non-lockstep with Verilator runs in about 2 hours
|
||||
addTests(tests_buildrootbootlockstep, lockstepsim) # lockstep with Questa and ImperasDV runs overnight
|
||||
addTests(tests_buildrootbootlockstep, lockstepsim, coverStr, configs) # lockstep with Questa and ImperasDV runs overnight
|
||||
|
||||
if (args.ccov): # only run RV64GC tests on Questa in code coverage mode
|
||||
addTestsByDir(WALLY+"/addins/cvw-arch-verif/tests/lockstep/rv64/", "rv64gc", coveragesim)
|
||||
addTestsByDir(WALLY+"/addins/cvw-arch-verif/tests/lockstep/priv/rv64/", "rv64gc", coveragesim)
|
||||
addTestsByDir(WALLY+"/tests/coverage/", "rv64gc", coveragesim)
|
||||
elif (args.fcov): # run tests in lockstep in functional coverage mode
|
||||
addTestsByDir(WALLY+"/addins/cvw-arch-verif/tests/lockstep/rv32/", "rv32gc", coveragesim)
|
||||
addTestsByDir(WALLY+"/addins/cvw-arch-verif/tests/lockstep/rv64/", "rv64gc", coveragesim)
|
||||
addTestsByDir(WALLY+"/addins/cvw-arch-verif/tests/lockstep/priv/rv32/", "rv32gc", coveragesim)
|
||||
addTestsByDir(WALLY+"/addins/cvw-arch-verif/tests/lockstep/priv/rv64/", "rv64gc", coveragesim)
|
||||
elif (args.breker):
|
||||
addTestsByDir(WALLY+"/tests/breker/work", "breker", "questa", brekerMode=1)
|
||||
else:
|
||||
if args.ccov: # only run RV64GC tests on Questa in code coverage mode
|
||||
addTestsByDir(f"{archVerifDir}/tests/lockstep/rv64/", "rv64gc", coveragesim, coverStr, configs)
|
||||
addTestsByDir(f"{archVerifDir}/tests/lockstep/priv/rv64/", "rv64gc", coveragesim, coverStr, configs)
|
||||
addTestsByDir(WALLY+"/tests/coverage/", "rv64gc", coveragesim, coverStr, configs)
|
||||
elif args.fcov: # run tests in lockstep in functional coverage mode
|
||||
addTestsByDir(f"{archVerifDir}/tests/lockstep/rv32/", "rv32gc", coveragesim, coverStr, configs)
|
||||
addTestsByDir(f"{archVerifDir}/tests/lockstep/rv64/", "rv64gc", coveragesim, coverStr, configs)
|
||||
addTestsByDir(f"{archVerifDir}/tests/lockstep/priv/rv32/", "rv32gc", coveragesim, coverStr, configs)
|
||||
addTestsByDir(f"{archVerifDir}/tests/lockstep/priv/rv64/", "rv64gc", coveragesim, coverStr, configs)
|
||||
elif args.breker:
|
||||
addTestsByDir(WALLY+"/tests/breker/work", "breker", "questa", coverStr, configs, brekerMode=1)
|
||||
elif not args.testfloat:
|
||||
for sim in sims:
|
||||
if (not (args.buildroot and sim == lockstepsim)): # skip short buildroot sim if running long one
|
||||
addTests(tests_buildrootshort, sim)
|
||||
addTests(tests, sim)
|
||||
addTests(tests64gc_nofp, sim)
|
||||
addTests(tests64gc_fp, sim)
|
||||
if not (args.buildroot and sim == lockstepsim): # skip short buildroot sim if running long one
|
||||
addTests(tests_buildrootshort, sim, coverStr, configs)
|
||||
addTests(standard_tests, sim, coverStr, configs)
|
||||
|
||||
# run derivative configurations and lockstep tests in nightly regression
|
||||
if (args.nightly):
|
||||
addTestsByDir(WALLY+"/tests/coverage", "rv64gc", lockstepsim, lockstepMode=1)
|
||||
addTestsByDir(WALLY+"/tests/riscof/work/wally-riscv-arch-test/rv64i_m", "rv64gc", lockstepsim, lockstepMode=1)
|
||||
addTestsByDir(WALLY+"/tests/riscof/work/wally-riscv-arch-test/rv32i_m", "rv32gc", lockstepsim, lockstepMode=1)
|
||||
addTests(derivconfigtests, defaultsim)
|
||||
if args.nightly:
|
||||
addTestsByDir(WALLY+"/tests/coverage", "rv64gc", lockstepsim, coverStr, configs, lockstepMode=1)
|
||||
addTestsByDir(WALLY+"/tests/riscof/work/wally-riscv-arch-test/rv64i_m", "rv64gc", lockstepsim, coverStr, configs, lockstepMode=1)
|
||||
addTestsByDir(WALLY+"/tests/riscof/work/wally-riscv-arch-test/rv32i_m", "rv32gc", lockstepsim, coverStr, configs, lockstepMode=1)
|
||||
addTests(derivconfigtests, defaultsim, coverStr, configs)
|
||||
# addTests(bpredtests, defaultsim) # This is currently broken in regression due to something related to the new wsim script.
|
||||
|
||||
# testfloat tests
|
||||
if (args.testfloat): # for testfloat alone, just run testfloat tests
|
||||
configs = []
|
||||
if (args.testfloat or args.nightly): # for nightly, run testfloat along with others
|
||||
testfloatsim = "questa" # change to Verilator when Issue #707 about testfloat not running Verilator is resolved
|
||||
testfloatconfigs = ["fdqh_rv64gc", "fdq_rv64gc", "fdh_rv64gc", "fd_rv64gc", "fh_rv64gc", "f_rv64gc", "fdqh_rv32gc", "f_rv32gc"]
|
||||
for config in testfloatconfigs:
|
||||
for config in testfloatconfigs + testfloatdivconfigs:
|
||||
if config in testfloatconfigs:
|
||||
tests = ["div", "sqrt", "add", "sub", "mul", "cvtint", "cvtfp", "fma", "cmp"]
|
||||
if ("f_" in config):
|
||||
else:
|
||||
tests = ["div", "sqrt", "cvtint", "cvtfp"]
|
||||
if "f_" in config:
|
||||
tests.remove("cvtfp")
|
||||
for test in tests:
|
||||
sim_log = WALLY + "/sim/" + testfloatsim + "/logs/"+config+"_"+test+".log"
|
||||
sim_log = f"{regressionDir}/{testfloatsim}/logs/{config}_{test}.log"
|
||||
tc = TestCase(
|
||||
name=test,
|
||||
variant=config,
|
||||
cmd="wsim --tb testbench_fp --sim " + testfloatsim + " " + config + " " + test + " > " + sim_log,
|
||||
cmd=f"wsim --tb testbench_fp --sim {testfloatsim} {config} {test} > {sim_log}",
|
||||
grepstr="All Tests completed with 0 errors",
|
||||
grepfile = sim_log)
|
||||
configs.append(tc)
|
||||
return configs
|
||||
|
||||
|
||||
testfloatdivconfigs = [
|
||||
"fdh_div_2_1_rv32gc", "fdh_div_2_1_rv64gc", "fdh_div_2_2_rv32gc",
|
||||
"fdh_div_2_2_rv64gc", "fdh_div_2_4_rv32gc", "fdh_div_2_4_rv64gc",
|
||||
"fdh_div_4_1_rv32gc", "fdh_div_4_1_rv64gc", "fdh_div_4_2_rv32gc",
|
||||
"fdh_div_4_2_rv64gc", "fdh_div_4_4_rv32gc", "fdh_div_4_4_rv64gc",
|
||||
"fd_div_2_1_rv32gc", "fd_div_2_1_rv64gc", "fd_div_2_2_rv32gc",
|
||||
"fd_div_2_2_rv64gc", "fd_div_2_4_rv32gc", "fd_div_2_4_rv64gc",
|
||||
"fd_div_4_1_rv32gc", "fd_div_4_1_rv64gc", "fd_div_4_2_rv32gc",
|
||||
"fd_div_4_2_rv64gc", "fd_div_4_4_rv32gc", "fd_div_4_4_rv64gc",
|
||||
"fdqh_div_2_1_rv32gc", "fdqh_div_2_1_rv64gc", "fdqh_div_2_2_rv32gc",
|
||||
"fdqh_div_2_2_rv64gc", "fdqh_div_2_4_rv32gc", "fdqh_div_2_4_rv64gc",
|
||||
"fdqh_div_4_1_rv32gc", "fdqh_div_4_1_rv64gc", "fdqh_div_4_2_rv32gc",
|
||||
"fdqh_div_4_2_rv64gc", "fdqh_div_4_4_rv32gc", "fdqh_div_4_4_rv64gc",
|
||||
"fdq_div_2_1_rv32gc", "fdq_div_2_1_rv64gc", "fdq_div_2_2_rv32gc",
|
||||
"fdq_div_2_2_rv64gc", "fdq_div_2_4_rv32gc", "fdq_div_2_4_rv64gc",
|
||||
"fdq_div_4_1_rv32gc", "fdq_div_4_1_rv64gc", "fdq_div_4_2_rv32gc",
|
||||
"fdq_div_4_2_rv64gc", "fdq_div_4_4_rv32gc", "fdq_div_4_4_rv64gc",
|
||||
"fh_div_2_1_rv32gc", "fh_div_2_1_rv64gc", "fh_div_2_2_rv32gc",
|
||||
"fh_div_2_2_rv64gc", "fh_div_2_4_rv32gc", "fh_div_2_4_rv64gc",
|
||||
"fh_div_4_1_rv32gc", "fh_div_4_1_rv64gc", "fh_div_4_2_rv32gc",
|
||||
"fh_div_4_2_rv64gc", "fh_div_4_4_rv32gc", "fh_div_4_4_rv64gc",
|
||||
"f_div_2_1_rv32gc", "f_div_2_1_rv64gc", "f_div_2_2_rv32gc",
|
||||
"f_div_2_2_rv64gc", "f_div_2_4_rv32gc", "f_div_2_4_rv64gc",
|
||||
"f_div_4_1_rv32gc", "f_div_4_1_rv64gc", "f_div_4_2_rv32gc",
|
||||
"f_div_4_2_rv64gc", "f_div_4_4_rv32gc", "f_div_4_4_rv64gc"
|
||||
]
|
||||
for config in testfloatdivconfigs:
|
||||
# div test case
|
||||
tests = ["div", "sqrt", "cvtint", "cvtfp"]
|
||||
if ("f_" in config):
|
||||
tests.remove("cvtfp")
|
||||
for test in tests:
|
||||
sim_log = WALLY + "/sim/questa/logs/"+config+"_"+test+".log"
|
||||
tc = TestCase(
|
||||
name=test,
|
||||
variant=config,
|
||||
cmd="wsim --tb testbench_fp " + config + " " + test + " > " + sim_log,
|
||||
grepstr="All Tests completed with 0 errors",
|
||||
grepfile = WALLY + "/sim/questa/logs/"+config+"_"+test+".log")
|
||||
configs.append(tc)
|
||||
|
||||
|
||||
def main():
|
||||
"""Run the tests and count the failures"""
|
||||
global configs, args
|
||||
os.chdir(regressionDir)
|
||||
dirs = ["questa/logs", "questa/wkdir", "verilator/logs", "verilator/wkdir", "vcs/logs", "vcs/wkdir"]
|
||||
def makeDirs(sims):
|
||||
for sim in sims:
|
||||
dirs = [f"{regressionDir}/{sim}/wkdir", f"{regressionDir}/{sim}/logs"]
|
||||
for d in dirs:
|
||||
try:
|
||||
os.system('rm -rf %s' % d)
|
||||
os.mkdir(d)
|
||||
except:
|
||||
pass
|
||||
if args.ccov:
|
||||
TIMEOUT_DUR = 20*60 # seconds
|
||||
os.system('rm -f questa/ucdb/* questa/cov/*')
|
||||
elif args.fcov:
|
||||
TIMEOUT_DUR = 8*60
|
||||
os.system('rm -f questa/fcov_ucdb/* questa/fcov_logs/* questa/fcov/*')
|
||||
elif args.buildroot:
|
||||
TIMEOUT_DUR = 60*1440 # 1 day
|
||||
elif args.testfloat:
|
||||
TIMEOUT_DUR = 30*60 # seconds
|
||||
elif args.nightly:
|
||||
TIMEOUT_DUR = 30*60 # seconds
|
||||
else:
|
||||
TIMEOUT_DUR = 10*60 # seconds
|
||||
shutil.rmtree(d)
|
||||
os.makedirs(d, exist_ok=True)
|
||||
|
||||
|
||||
def main(args):
|
||||
sims, coverStr, TIMEOUT_DUR = process_args(args)
|
||||
configs = selectTests(args, sims, coverStr)
|
||||
# Scale the number of concurrent processes to the number of test cases, but
|
||||
# max out at a limited number of concurrent processes to not overwhelm the system
|
||||
# right now fcov, ccov, nightly all use Imperas
|
||||
if (args.ccov or args.fcov or args.nightly):
|
||||
ImperasDVLicenseCount = 16 # limit number of concurrent processes to avoid overloading ImperasDV licenses
|
||||
else:
|
||||
ImperasDVLicenseCount = 10000 # effectively no license limit for non-lockstep tests
|
||||
# right now fcov and nightly use Imperas
|
||||
ImperasDVLicenseCount = 16 if args.fcov or args.nightly else 10000
|
||||
with Pool(processes=min(len(configs),multiprocessing.cpu_count(), ImperasDVLicenseCount)) as pool:
|
||||
num_fail = 0
|
||||
results = {}
|
||||
@ -567,22 +498,24 @@ def main():
|
||||
for (config,result) in results.items():
|
||||
try:
|
||||
num_fail+=result.get(timeout=TIMEOUT_DUR)
|
||||
except TimeoutError:
|
||||
except MPTimeoutError:
|
||||
pool.terminate()
|
||||
pool.join()
|
||||
num_fail+=1
|
||||
print(f"{bcolors.FAIL}%s: Timeout - runtime exceeded %d seconds{bcolors.ENDC}" % (config.cmd, TIMEOUT_DUR))
|
||||
print(f"{bcolors.FAIL}{config.cmd}: Timeout - runtime exceeded {TIMEOUT_DUR} seconds{bcolors.ENDC}")
|
||||
|
||||
# Coverage report
|
||||
if args.ccov:
|
||||
os.system('make QuestaCodeCoverage')
|
||||
os.system(f"make -C {regressionDir}/QuestaCodeCoverage")
|
||||
if args.fcov:
|
||||
os.system('make -C '+WALLY+'/addins/cvw-arch-verif merge')
|
||||
os.system(f"make -C {archVerifDir} merge")
|
||||
# Count the number of failures
|
||||
if num_fail:
|
||||
print(f"{bcolors.FAIL}Regression failed with %s failed configurations{bcolors.ENDC}" % num_fail)
|
||||
print(f"{bcolors.FAIL}Regression failed with {num_fail} failed configurations{bcolors.ENDC}")
|
||||
else:
|
||||
print(f"{bcolors.OKGREEN}SUCCESS! All tests ran without failures{bcolors.ENDC}")
|
||||
return num_fail
|
||||
|
||||
if __name__ == '__main__':
|
||||
exit(main())
|
||||
args = parse_args()
|
||||
sys.exit(main(args))
|
||||
|
22
bin/wsim
22
bin/wsim
@ -16,7 +16,7 @@ import os
|
||||
import sys
|
||||
|
||||
# Global variable
|
||||
WALLY = os.environ.get('WALLY')
|
||||
WALLY = os.environ.get("WALLY")
|
||||
|
||||
def parseArgs():
|
||||
parser = argparse.ArgumentParser()
|
||||
@ -41,13 +41,13 @@ def validateArgs(args):
|
||||
if not args.testsuite and not args.elf:
|
||||
print("Error: Missing test suite or ELF file")
|
||||
sys.exit(1)
|
||||
if any([args.lockstep, args.lockstepverbose, args.fcov]) and not (args.testsuite.endswith('.elf') or args.elf) and args.testsuite != "buildroot":
|
||||
if any([args.lockstep, args.lockstepverbose, args.fcov]) and not (args.testsuite.endswith(".elf") or args.elf) and args.testsuite != "buildroot":
|
||||
print(f"Invalid Options. Cannot run a testsuite, {args.testsuite} with lockstep or fcov. Must run a single elf or buildroot.")
|
||||
sys.exit(1)
|
||||
elif any([args.gui, args.ccov, args.fcov, args.lockstep, args.lockstepverbose]) and args.sim not in ["questa", "vcs"]:
|
||||
print("Option only supported for Questa and VCS")
|
||||
sys.exit(1)
|
||||
elif (args.tb == "testbench_fp" and args.sim != "questa"):
|
||||
elif args.tb == "testbench_fp" and args.sim != "questa":
|
||||
print("Error: testbench_fp presently only supported by Questa, not VCS or Verilator, because of a touchy testbench")
|
||||
sys.exit(1)
|
||||
elif (args.config == "breker" and args.sim != "questa"):
|
||||
@ -61,11 +61,11 @@ def elfFileCheck(args):
|
||||
elif args.elf:
|
||||
print(f"ELF file not found: {args.elf}")
|
||||
sys.exit(1)
|
||||
elif args.testsuite.endswith('.elf'): # No --elf argument; check if testsuite has a .elf extension and use that instead
|
||||
elif args.testsuite.endswith(".elf"): # No --elf argument; check if testsuite has a .elf extension and use that instead
|
||||
if os.path.isfile(args.testsuite):
|
||||
ElfFile = os.path.abspath(args.testsuite)
|
||||
# extract the elf name from the path to be the test suite
|
||||
fields = args.testsuite.rsplit('/', 3)
|
||||
fields = args.testsuite.rsplit("/", 3)
|
||||
# if the name is just ref.elf in a deep path (riscv-arch-test/wally-riscv-arch-test), then use the directory name as the test suite to make it unique; otherwise work directory will have duplicates.
|
||||
if "breker" in args.testsuite:
|
||||
args.testsuite = fields[-1]
|
||||
@ -74,8 +74,8 @@ def elfFileCheck(args):
|
||||
args.testsuite = f"{fields[1]}_{fields[3]}"
|
||||
else:
|
||||
args.testsuite = f"{fields[2]}_{fields[3]}"
|
||||
elif '/' in args.testsuite:
|
||||
args.testsuite=args.testsuite.rsplit('/', 1)[1] # strip off path if present
|
||||
elif "/" in args.testsuite:
|
||||
args.testsuite = args.testsuite.rsplit("/", 1)[1] # strip off path if present
|
||||
else:
|
||||
print(f"ELF file not found: {args.testsuite}")
|
||||
sys.exit(1)
|
||||
@ -116,9 +116,9 @@ def prepSim(args, ElfFile):
|
||||
defineList.append("+define+USE_TREK_DV")
|
||||
argsList.append(f"+TREK_TBX_FILE={ElfFileNoExtension}.tbx")
|
||||
# Combine into a single string
|
||||
args.args += " ".join(argsList)
|
||||
args.params += " ".join(paramsList)
|
||||
args.define += " ".join(defineList)
|
||||
args.args += " " + " ".join(argsList)
|
||||
args.params += " " + " ".join(paramsList)
|
||||
args.define += " " + " ".join(defineList)
|
||||
flags = " ".join(flagsList)
|
||||
return flags, prefix
|
||||
|
||||
@ -154,7 +154,7 @@ def runQuesta(args, flags, prefix):
|
||||
args.params = fr'--params \"{args.params}\"'
|
||||
if args.define:
|
||||
args.define = fr'--define \"{args.define}\"'
|
||||
# Questa cannot accept more than 9 arguments. fcov implies lockstep
|
||||
# fcov implies lockstep
|
||||
cmd = f"do wally.do {args.config} {args.testsuite} {args.tb} {args.args} {args.params} {args.define} {flags}"
|
||||
cmd = f'cd $WALLY/sim/questa; {prefix} vsim {"-c" if not args.gui else ""} -do "{cmd}"'
|
||||
print(f"Running Questa with command: {cmd}")
|
||||
|
@ -1,4 +1,5 @@
|
||||
import shutil, os
|
||||
import shutil
|
||||
import os
|
||||
|
||||
# if WALLY is defined, then get it
|
||||
WALLY_HOME = os.getenv("WALLY")
|
||||
|
@ -13,7 +13,7 @@ def main(args):
|
||||
probenum = 0
|
||||
countLines = 1
|
||||
|
||||
with open(args[0],'r') as xdcfile, open(args[1], 'w') as outfile:
|
||||
with open(args[0]) as xdcfile, open(args[1], 'w') as outfile:
|
||||
Lines = xdcfile.readlines()
|
||||
for line in Lines:
|
||||
t = re.sub("probe[0-9]+", f"probe{probenum}",line)
|
||||
|
@ -53,7 +53,7 @@ add wave -noupdate -group {Execution Stage} /testbench/dut/core/ifu/PCE
|
||||
add wave -noupdate -group {Execution Stage} /testbench/dut/core/ifu/InstrE
|
||||
add wave -noupdate -group {Execution Stage} /testbench/InstrEName
|
||||
add wave -noupdate -group {Execution Stage} /testbench/dut/core/ieu/c/InstrValidE
|
||||
add wave -noupdate -group {Execution Stage} /testbench/FunctionName/FunctionName/FunctionName
|
||||
add wave -noupdate -group {Execution Stage} /testbench/functionName/functionName/FunctionName
|
||||
add wave -noupdate -expand -group {Memory Stage} /testbench/dut/core/PCM
|
||||
add wave -noupdate -expand -group {Memory Stage} /testbench/dut/core/InstrM
|
||||
add wave -noupdate -expand -group {Memory Stage} /testbench/InstrMName
|
||||
|
@ -67,8 +67,8 @@ def main():
|
||||
parser.add_argument('-d', "--dist", action='store_true', help="Report distribution of operations")
|
||||
parser.add_argument('-s', "--sim", help="Simulator", choices=["questa", "verilator", "vcs"], default="verilator")
|
||||
args = parser.parse_args()
|
||||
simargs = "I_CACHE_ADDR_LOGGER=1\\\'b1 D_CACHE_ADDR_LOGGER=1\\\'b1"
|
||||
testcmd = "wsim --sim " + args.sim + " rv64gc {} --params \"" + simargs + "\" > /dev/null"
|
||||
simargs = "I_CACHE_ADDR_LOGGER=1\\'b1 D_CACHE_ADDR_LOGGER=1\\'b1"
|
||||
testcmd = "wsim --sim " + args.sim + ' rv64gc {} --params "' + simargs + '" > /dev/null'
|
||||
#cachecmd = "CacheSim.py 64 4 56 44 -f {} --verbose"
|
||||
cachecmd = "CacheSim.py 64 4 56 44 -f {}"
|
||||
mismatches = 0
|
||||
|
@ -1,32 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
import os,sys,subprocess
|
||||
from datetime import datetime, timezone, timedelta
|
||||
|
||||
if not os.path.isfile(sys.path[0]+'/slack-webhook-url.txt'):
|
||||
print('==============================================================')
|
||||
print(' HOWDY! ')
|
||||
print('slack-notifier.py can help let you know when your sim is done.')
|
||||
print('To make it work, please supply your Slack bot webhook URL in:')
|
||||
print(sys.path[0]+'/slack-webhook-url.txt')
|
||||
print('Tutorial for slack webhook urls: https://bit.ly/BenSlackNotifier')
|
||||
print('==============================================================')
|
||||
else:
|
||||
urlFile = open(sys.path[0]+'/slack-webhook-url.txt','r')
|
||||
url = urlFile.readline().strip('\n')
|
||||
|
||||
# Traverse 3 parents up the process tree
|
||||
result = subprocess.check_output('ps -o ppid -p $PPID',shell=True)
|
||||
PPID2 = str(result).split('\\n')[1]
|
||||
result = subprocess.check_output('ps -o ppid -p '+PPID2,shell=True)
|
||||
PPID3 = str(result).split('\\n')[1]
|
||||
# Get command name
|
||||
result = subprocess.check_output('ps -o cmd -p '+PPID3,shell=True)
|
||||
cmdName = str(result).split('\\n')[1]
|
||||
# Get current time
|
||||
timezone_offset = -8.0 # Pacific Standard Time (UTC−08:00)
|
||||
tzinfo = timezone(timedelta(hours=timezone_offset))
|
||||
time = datetime.now(tzinfo).strftime('%I:%M %p')
|
||||
# Send message
|
||||
message = 'Command `'+cmdName+'` completed at '+time+' PST'
|
||||
result = subprocess.run('curl -X POST -H \'Content-type: application/json\' --data \'{"text":"'+message+'"}\' '+url,shell=True,stdout=subprocess.DEVNULL,stderr=subprocess.DEVNULL)
|
||||
print('Simulation stopped. Sending Slack message.')
|
@ -12,7 +12,7 @@ import subprocess
|
||||
import sys
|
||||
|
||||
# Global variables
|
||||
WALLY = os.environ.get('WALLY')
|
||||
WALLY = os.environ.get("WALLY")
|
||||
simdir = f"{WALLY}/sim/vcs"
|
||||
cfgdir = f"{WALLY}/config"
|
||||
srcdir = f"{WALLY}/src"
|
||||
@ -21,10 +21,10 @@ logdir = f"{simdir}/logs"
|
||||
|
||||
# run a Linux command and return the result as a string in a form that VCS can use
|
||||
def runFindCommand(cmd):
|
||||
res = subprocess.check_output(cmd, shell=True, )
|
||||
res = subprocess.check_output(cmd, shell=True)
|
||||
res = str(res)
|
||||
res = res.replace("\\n", " ") # replace newline with space
|
||||
res = res.replace("\'", "") # strip off quotation marks
|
||||
res = res.replace("'", "") # strip off quotation marks
|
||||
res = res[1:] # strip off leading b from byte string
|
||||
return res
|
||||
|
||||
@ -42,20 +42,20 @@ def parseArgs():
|
||||
#parser.add_argument("--gui", "-g", help="Simulate with GUI", action="store_true") # GUI not yet implemented
|
||||
return parser.parse_args()
|
||||
|
||||
def createDirs(args):
|
||||
wkdir = f"{simdir}/wkdir/{args.config}_{args.testsuite}"
|
||||
covdir = f"{simdir}/cov/{args.config}_{args.testsuite}"
|
||||
def createDirs(config, testsuite):
|
||||
wkdir = f"{simdir}/wkdir/{config}_{testsuite}"
|
||||
covdir = f"{simdir}/cov/{config}_{testsuite}"
|
||||
os.makedirs(wkdir, exist_ok=True)
|
||||
os.makedirs(covdir, exist_ok=True)
|
||||
os.makedirs(logdir, exist_ok=True)
|
||||
return wkdir, covdir
|
||||
return wkdir
|
||||
|
||||
def generateFileList():
|
||||
def generateFileList(testbench):
|
||||
rtlsrc_cmd = f'find {srcdir} -name "*.sv" ! -path "{srcdir}/generic/mem/rom1p1r_128x64.sv" ! -path "{srcdir}/generic/mem/ram2p1r1wbe_128x64.sv" ! -path "{srcdir}/generic/mem/rom1p1r_128x32.sv" ! -path "{srcdir}/generic/mem/ram2p1r1wbe_2048x64.sv"'
|
||||
rtlsrc_files = runFindCommand(rtlsrc_cmd)
|
||||
tbcommon_cmd = f'find {tbdir}/common -name "*.sv"'
|
||||
tbcommon_files = runFindCommand(tbcommon_cmd)
|
||||
tb_file = f'{tbdir}/{args.tb}.sv'
|
||||
tb_file = f"{tbdir}/{testbench}.sv"
|
||||
return f"{tb_file} {rtlsrc_files} {tbcommon_files}"
|
||||
|
||||
def processArgs(wkdir, args):
|
||||
@ -84,10 +84,7 @@ def setupParamOverrides(wkdir, args):
|
||||
with open(paramOverrideFile, "w") as f:
|
||||
for param in args.params.split():
|
||||
[param, value] = param.split("=")
|
||||
if fr"\'" in value: # for bit values
|
||||
value = value.replace(fr"\'", "'")
|
||||
else: # for strings
|
||||
value = f'"{value}"'
|
||||
value = value.replace("\\'", "'") if "\\'" in value else f'"{value}"' # transform quotes/bit indicators
|
||||
f.write(f"assign {value} {args.tb}/{param}\n")
|
||||
return f" -parameters {wkdir}/param_overrides.txt "
|
||||
|
||||
@ -98,21 +95,24 @@ def setupCommands(wkdir, rtlFiles, compileOptions, simvOptions, args):
|
||||
simvCMD = f"{wkdir}/sim_out +TEST={args.testsuite} {args.args} -no_save {simvOptions}"
|
||||
return vcsCMD, simvCMD
|
||||
|
||||
def runVCS(wkdir, vcsCMD, simvCMD):
|
||||
def runVCS(vcsCMD, simvCMD):
|
||||
print(f"Executing: {vcsCMD}")
|
||||
subprocess.run(vcsCMD, shell=True)
|
||||
subprocess.run(simvCMD, shell=True)
|
||||
if (args.ccov):
|
||||
COV_RUN = f"urg -dir {wkdir}/coverage.vdb -format text -report IndividualCovReport/{args.config}_{args.testsuite}"
|
||||
subprocess.run(COV_RUN, shell=True)
|
||||
subprocess.run(vcsCMD, shell=True, check=True)
|
||||
subprocess.run(simvCMD, shell=True, check=True)
|
||||
|
||||
def runCoverage(wkdir, config, testsuite):
|
||||
COV_RUN = f"urg -dir {wkdir}/coverage.vdb -format text -report IndividualCovReport/{config}_{testsuite}"
|
||||
subprocess.run(COV_RUN, shell=True, check=True)
|
||||
|
||||
def main(args):
|
||||
print(f"run_vcs Config={args.config} tests={args.testsuite} lockstep={args.lockstep} args='{args.args}' params='{args.params}' define='{args.define}'")
|
||||
wkdir, covdir = createDirs(args)
|
||||
rtlFiles = generateFileList()
|
||||
wkdir = createDirs(args.config, args.testsuite)
|
||||
rtlFiles = generateFileList(args.tb)
|
||||
compileOptions, simvOptions = processArgs(wkdir, args)
|
||||
vcsCMD, simvCMD = setupCommands(wkdir, rtlFiles, compileOptions, simvOptions, args)
|
||||
runVCS(wkdir, vcsCMD, simvCMD)
|
||||
runVCS(vcsCMD, simvCMD)
|
||||
if args.ccov:
|
||||
runCoverage(wkdir, args.config, args.testsuite)
|
||||
|
||||
if __name__ == "__main__":
|
||||
args = parseArgs()
|
||||
|
@ -27,7 +27,7 @@ def synthsintocsv():
|
||||
specReg = re.compile('[a-zA-Z0-9]+')
|
||||
metricReg = re.compile('-?\d+\.\d+[e]?[-+]?\d*')
|
||||
|
||||
file = open("Summary.csv", "w")
|
||||
with open("Summary.csv", "w") as file:
|
||||
writer = csv.writer(file)
|
||||
writer.writerow(['Width', 'Config', 'Mod', 'Tech', 'Target Freq', 'Delay', 'Area'])
|
||||
|
||||
@ -36,10 +36,7 @@ def synthsintocsv():
|
||||
# print("From " + oneSynth + " Find ")
|
||||
# for d in descrip:
|
||||
# print(d)
|
||||
if (descrip[3] == "sram"):
|
||||
base = 4
|
||||
else:
|
||||
base = 3
|
||||
base = 4 if descrip[3] == "sram" else 3
|
||||
width = descrip[base][:4]
|
||||
config = descrip[base][4:]
|
||||
if descrip[base+1][-2:] == 'nm':
|
||||
@ -68,7 +65,6 @@ def synthsintocsv():
|
||||
delay = 1000/int(freq) - metrics[0]
|
||||
area = metrics[1]
|
||||
writer.writerow([width, config, mod, tech, freq, delay, area])
|
||||
file.close()
|
||||
|
||||
|
||||
def synthsfromcsv(filename):
|
||||
@ -93,7 +89,7 @@ def freqPlot(tech, width, config):
|
||||
|
||||
freqsL, delaysL, areasL = ([[], []] for i in range(3))
|
||||
for oneSynth in allSynths:
|
||||
if (width == oneSynth.width) & (config == oneSynth.config) & (tech == oneSynth.tech) & ('orig' == oneSynth.mod):
|
||||
if (width == oneSynth.width) & (config == oneSynth.config) & (tech == oneSynth.tech) & (oneSynth.mod == 'orig'):
|
||||
ind = (1000/oneSynth.delay < (0.95*oneSynth.freq)) # when delay is within target clock period
|
||||
freqsL[ind] += [oneSynth.freq]
|
||||
delaysL[ind] += [oneSynth.delay]
|
||||
@ -101,10 +97,7 @@ def freqPlot(tech, width, config):
|
||||
|
||||
fig, (ax1, ax2) = plt.subplots(2, 1, sharex=True)
|
||||
allFreqs = list(flatten(freqsL))
|
||||
if allFreqs != []:
|
||||
median = np.median(allFreqs)
|
||||
else:
|
||||
median = 0
|
||||
median = np.median(allFreqs) if allFreqs != [] else 0
|
||||
|
||||
for ind in [0,1]:
|
||||
areas = areasL[ind]
|
||||
@ -169,8 +162,7 @@ def plotFeatures(tech, width, config):
|
||||
delays, areas, labels = ([] for i in range(3))
|
||||
freq = techdict[tech].targfreq
|
||||
for oneSynth in allSynths:
|
||||
if (tech == oneSynth.tech) & (freq == oneSynth.freq):
|
||||
if (oneSynth.config == config) & (width == oneSynth.width):
|
||||
if (tech == oneSynth.tech) & (freq == oneSynth.freq) & (oneSynth.config == config) & (width == oneSynth.width):
|
||||
delays += [oneSynth.delay]
|
||||
areas += [oneSynth.area]
|
||||
labels += [oneSynth.mod]
|
||||
@ -282,4 +274,4 @@ if __name__ == '__main__':
|
||||
plotConfigs('sky130', mod='orig')
|
||||
plotConfigs('tsmc28psyn', mod='orig')
|
||||
normAreaDelay(mod='orig')
|
||||
os.system("./extractArea.pl");
|
||||
os.system("./extractArea.pl")
|
||||
|
@ -50,7 +50,7 @@ def synthsintocsv():
|
||||
specReg = re.compile("[a-zA-Z0-9]+")
|
||||
metricReg = re.compile("-?\d+\.\d+[e]?[-+]?\d*")
|
||||
|
||||
file = open("ppaData.csv", "w")
|
||||
with open("ppaData.csv", "w") as file:
|
||||
writer = csv.writer(file)
|
||||
writer.writerow(
|
||||
[
|
||||
@ -92,7 +92,6 @@ def synthsintocsv():
|
||||
[area, lpower, denergy] = [n / 2 for n in [area, lpower, denergy]]
|
||||
|
||||
writer.writerow([module, tech, width, freq, delay, area, lpower, denergy])
|
||||
file.close()
|
||||
|
||||
|
||||
def cleanup():
|
||||
@ -129,15 +128,12 @@ def getVals(tech, module, var, freq=None, width=None):
|
||||
works at a specified target frequency or if none is given, uses the synthesis with the best achievable delay for each width
|
||||
"""
|
||||
|
||||
if width != None:
|
||||
widthsToGet = width
|
||||
else:
|
||||
widthsToGet = widths
|
||||
widthsToGet = width if width is not None else widths
|
||||
|
||||
metric = []
|
||||
widthL = []
|
||||
|
||||
if freq != None:
|
||||
if freq is not None:
|
||||
for oneSynth in allSynths:
|
||||
if (
|
||||
(oneSynth.freq == freq)
|
||||
@ -171,21 +167,15 @@ def csvOfBest(filename):
|
||||
m = np.Inf # large number to start
|
||||
best = None
|
||||
for oneSynth in allSynths: # best achievable, rightmost green
|
||||
if (
|
||||
(oneSynth.width == w)
|
||||
& (oneSynth.tech == tech)
|
||||
& (oneSynth.module == mod)
|
||||
):
|
||||
if (oneSynth.delay < m) & (
|
||||
1000 / oneSynth.delay > oneSynth.freq
|
||||
):
|
||||
if (oneSynth.width == w) & (oneSynth.tech == tech) & (oneSynth.module == mod):
|
||||
if (oneSynth.delay < m) & (1000 / oneSynth.delay > oneSynth.freq):
|
||||
m = oneSynth.delay
|
||||
best = oneSynth
|
||||
|
||||
if (best != None) & (best not in bestSynths):
|
||||
if (best is not None) & (best not in bestSynths):
|
||||
bestSynths += [best]
|
||||
|
||||
file = open(filename, "w")
|
||||
with open(filename, "w") as file:
|
||||
writer = csv.writer(file)
|
||||
writer.writerow(
|
||||
[
|
||||
@ -201,7 +191,6 @@ def csvOfBest(filename):
|
||||
)
|
||||
for synth in bestSynths:
|
||||
writer.writerow(list(synth))
|
||||
file.close()
|
||||
return bestSynths
|
||||
|
||||
|
||||
@ -229,7 +218,7 @@ def genLegend(fits, coefs, r2=None, spec=None, ale=False):
|
||||
eq = ""
|
||||
ind = 0
|
||||
|
||||
for k in eqDict.keys():
|
||||
for k in eqDict:
|
||||
if k in fits:
|
||||
if str(coefsr[ind]) != "0":
|
||||
eq += " + " + coefsr[ind] + eqDict[k]
|
||||
@ -237,7 +226,7 @@ def genLegend(fits, coefs, r2=None, spec=None, ale=False):
|
||||
|
||||
eq = eq[3:] # chop off leading ' + '
|
||||
|
||||
if (r2 == None) or (spec == None):
|
||||
if (r2 is None) or (spec is None):
|
||||
return eq
|
||||
else:
|
||||
legend_elements = [lines.Line2D([0], [0], color=spec.color, label=eq)]
|
||||
@ -277,10 +266,7 @@ def oneMetricPlot(
|
||||
modFit = fitDict[module]
|
||||
fits = modFit[ale]
|
||||
|
||||
if freq:
|
||||
ls = "--"
|
||||
else:
|
||||
ls = "-"
|
||||
ls = "--" if freq else "-"
|
||||
|
||||
for spec in techSpecs:
|
||||
# print(f"Searching for module of spec {spec} and module {module} and var {var}")
|
||||
@ -339,7 +325,7 @@ def oneMetricPlot(
|
||||
ax.add_artist(ax.legend(handles=fullLeg, loc=legLoc))
|
||||
titleStr = (
|
||||
" (target " + str(freq) + "MHz)"
|
||||
if freq != None
|
||||
if freq is not None
|
||||
else " (best achievable delay)"
|
||||
)
|
||||
ax.set_title(module + titleStr)
|
||||
@ -403,7 +389,7 @@ def makeCoefTable():
|
||||
"""writes CSV with each line containing the coefficients for a regression fit
|
||||
to a particular combination of module, metric (including both techs, normalized)
|
||||
"""
|
||||
file = open("ppaFitting.csv", "w")
|
||||
with open("ppaFitting.csv", "w") as file:
|
||||
writer = csv.writer(file)
|
||||
writer.writerow(
|
||||
["Module", "Metric", "Target", "1", "N", "N^2", "log2(N)", "Nlog2(N)", "R^2"]
|
||||
@ -436,8 +422,6 @@ def makeCoefTable():
|
||||
row = [module, var, target] + coefsToWrite + [r2]
|
||||
writer.writerow(row)
|
||||
|
||||
file.close()
|
||||
|
||||
|
||||
def sigfig(num, figs):
|
||||
return "{:g}".format(float("{:.{p}g}".format(num, p=figs)))
|
||||
@ -447,7 +431,7 @@ def makeEqTable():
|
||||
"""writes CSV with each line containing the equations for fits for each metric
|
||||
to a particular module (including both techs, normalized)
|
||||
"""
|
||||
file = open("ppaEquations.csv", "w")
|
||||
with open("ppaEquations.csv", "w") as file:
|
||||
writer = csv.writer(file)
|
||||
writer.writerow(
|
||||
[
|
||||
@ -486,9 +470,6 @@ def makeEqTable():
|
||||
row = [module] + eqs
|
||||
writer.writerow(row)
|
||||
|
||||
file.close()
|
||||
|
||||
|
||||
def genFuncs(fits="clsgn"):
|
||||
"""helper function for regress()
|
||||
returns array of functions with one for each term desired in the regression fit
|
||||
@ -719,7 +700,7 @@ def plotPPA(mod, freq=None, norm=True, aleOpt=False):
|
||||
else:
|
||||
axs[i, j].legend(handles=leg, handlelength=1.5)
|
||||
|
||||
titleStr = " (target " + str(freq) + "MHz)" if freq != None else ""
|
||||
titleStr = f" (target {freq} MHz)" if freq is not None else ""
|
||||
plt.suptitle(mod + titleStr)
|
||||
plt.tight_layout(pad=0.05, w_pad=1, h_pad=0.5, rect=(0, 0, 1, 0.97))
|
||||
|
||||
@ -819,10 +800,7 @@ def stdDevError():
|
||||
norm = techdict[var]
|
||||
metL += [m / norm for m in metric]
|
||||
|
||||
if ale:
|
||||
ws = [w / normAddWidth for w in widths]
|
||||
else:
|
||||
ws = widths
|
||||
ws = [w / normAddWidth for w in widths] if ale else widths
|
||||
ws = ws * 2
|
||||
mat = []
|
||||
for w in ws:
|
||||
@ -896,7 +874,7 @@ if __name__ == "__main__":
|
||||
"flop": ["c", "l", "l"],
|
||||
"binencoder": ["cg", "l", "l"],
|
||||
}
|
||||
fitDict.update(dict.fromkeys(["mux2", "mux4", "mux8"], ["cg", "l", "l"]))
|
||||
fitDict.update({key: ["cg", "l", "l"] for key in ["mux2", "mux4", "mux8"]})
|
||||
|
||||
TechSpec = namedtuple("TechSpec", "tech color shape delay area lpower denergy")
|
||||
# FO4 delay information information
|
||||
|
@ -11,7 +11,7 @@ from multiprocessing import Pool
|
||||
from ppaAnalyze import synthsfromcsv
|
||||
|
||||
def runCommand(module, width, tech, freq):
|
||||
command = "make synth DESIGN={} WIDTH={} TECH={} DRIVE=INV FREQ={} MAXOPT=1 MAXCORES=1".format(module, width, tech, freq)
|
||||
command = f"make synth DESIGN={module} WIDTH={width} TECH={tech} DRIVE=INV FREQ={freq} MAXOPT=1 MAXCORES=1"
|
||||
subprocess.call(command, shell=True)
|
||||
|
||||
def deleteRedundant(synthsToRun):
|
||||
@ -19,7 +19,7 @@ def deleteRedundant(synthsToRun):
|
||||
synthStr = "rm -rf runs/{}_{}_rv32e_{}_{}_*"
|
||||
for synth in synthsToRun:
|
||||
bashCommand = synthStr.format(*synth)
|
||||
outputCPL = subprocess.check_output(['bash','-c', bashCommand])
|
||||
subprocess.check_output(['bash','-c', bashCommand])
|
||||
|
||||
def freqSweep(module, width, tech):
|
||||
synthsToRun = []
|
||||
|
@ -15,14 +15,13 @@ import os
|
||||
parser = argparse.ArgumentParser()
|
||||
|
||||
parser.add_argument("DESIGN")
|
||||
parser.add_argument("HDLPATH");
|
||||
parser.add_argument("HDLPATH")
|
||||
|
||||
args=parser.parse_args()
|
||||
|
||||
fin_path = glob.glob(f"{os.getenv('WALLY')}/src/**/{args.DESIGN}.sv",recursive=True)[0]
|
||||
|
||||
fin = open(fin_path, "r", encoding='utf-8')
|
||||
|
||||
with open(fin_path) as fin:
|
||||
lines = fin.readlines()
|
||||
|
||||
# keeps track of what line number the module header begins
|
||||
@ -35,7 +34,7 @@ lineModuleEnd = 0
|
||||
moduleName = ""
|
||||
|
||||
# string that will keep track of the running module header
|
||||
buf = "import cvw::*;\n`include \"config.vh\"\n`include \"parameter-defs.vh\"\n"
|
||||
buf = 'import cvw::*;\n`include "config.vh"\n`include "parameter-defs.vh"\n'
|
||||
|
||||
# are we writing into the buffer
|
||||
writeBuf=False
|
||||
@ -63,11 +62,5 @@ buf += f"\t{moduleName} #(P) dut(.*);\nendmodule"
|
||||
# path to wrapper
|
||||
wrapperPath = f"{args.HDLPATH}/{moduleName}wrapper.sv"
|
||||
|
||||
fout = open(wrapperPath, "w")
|
||||
|
||||
with open(wrapperPath, "w") as fout:
|
||||
fout.write(buf)
|
||||
|
||||
fin.close()
|
||||
fout.close()
|
||||
|
||||
#print(buf)
|
||||
|
@ -7,12 +7,9 @@ import argparse
|
||||
|
||||
def runSynth(config, mod, tech, freq, maxopt, usesram):
|
||||
global pool
|
||||
if (usesram):
|
||||
prefix = "syn_sram_"
|
||||
else:
|
||||
prefix = "syn_"
|
||||
prefix = "syn_sram_" if usesram else "syn_"
|
||||
cfg = prefix + config
|
||||
command = "make synth DESIGN=wallypipelinedcore CONFIG={} MOD={} TECH={} DRIVE=FLOP FREQ={} MAXOPT={} USESRAM={} MAXCORES=1".format(cfg, mod, tech, freq, maxopt, usesram)
|
||||
command = f"make synth DESIGN=wallypipelinedcore CONFIG={cfg} MOD={mod} TECH={tech} DRIVE=FLOP FREQ={freq} MAXOPT={maxopt} USESRAM={usesram} MAXCORES=1"
|
||||
pool.map(mask, [command])
|
||||
|
||||
def mask(command):
|
||||
|
@ -1,26 +0,0 @@
|
||||
///////////////////////////////////////////
|
||||
// checksignature.sv
|
||||
//
|
||||
// Written: David Harris David_Harris@hmc.edu
|
||||
// Modified: 14 June 2023
|
||||
//
|
||||
// Purpose: Verifies the memory signature.
|
||||
//
|
||||
// A component of the Wally configurable RISC-V project.
|
||||
//
|
||||
// Copyright (C) 2021 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.
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -23,7 +23,7 @@
|
||||
// and limitations under the License.
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
module FunctionName import cvw::*; #(parameter cvw_t P) (
|
||||
module functionName import cvw::*; #(parameter cvw_t P) (
|
||||
input logic reset,
|
||||
input logic clk,
|
||||
input string ProgramAddrMapFile,
|
||||
|
@ -84,11 +84,11 @@ module loggers import cvw::*; #(parameter cvw_t P,
|
||||
|
||||
always_comb
|
||||
if (TEST == "embench") begin
|
||||
StartSampleFirst = FunctionName.FunctionName.FunctionName == "start_trigger";
|
||||
EndSampleFirst = FunctionName.FunctionName.FunctionName == "stop_trigger";
|
||||
StartSampleFirst = functionName.functionName.FunctionName == "start_trigger";
|
||||
EndSampleFirst = functionName.functionName.FunctionName == "stop_trigger";
|
||||
end else if (TEST == "coremark") begin
|
||||
StartSampleFirst = FunctionName.FunctionName.FunctionName == "start_time";
|
||||
EndSampleFirst = FunctionName.FunctionName.FunctionName == "stop_time";
|
||||
StartSampleFirst = functionName.functionName.FunctionName == "start_time";
|
||||
EndSampleFirst = functionName.functionName.FunctionName == "stop_time";
|
||||
end else begin
|
||||
StartSampleFirst = reset;
|
||||
EndSampleFirst = '0;
|
||||
@ -106,22 +106,22 @@ module loggers import cvw::*; #(parameter cvw_t P,
|
||||
if(TEST == "embench") begin
|
||||
// embench runs warmup then runs start_trigger
|
||||
// embench end with stop_trigger.
|
||||
//assign StartSampleFirst = FunctionName.FunctionName.FunctionName == "start_trigger";
|
||||
//assign StartSampleFirst = functionName.functionName.FunctionName == "start_trigger";
|
||||
//flopr #(1) StartSampleReg(clk, reset, StartSampleFirst, StartSampleDelayed);
|
||||
//assign StartSample = StartSampleFirst & ~ StartSampleDelayed;
|
||||
|
||||
//assign EndSampleFirst = FunctionName.FunctionName.FunctionName == "stop_trigger";
|
||||
//assign EndSampleFirst = functionName.functionName.FunctionName == "stop_trigger";
|
||||
flopr #(1) EndSampleReg(clk, reset, EndSampleFirst, EndSampleDelayed);
|
||||
assign EndSample = EndSampleFirst & ~ EndSampleDelayed;
|
||||
|
||||
end else if(TEST == "coremark") begin
|
||||
// embench runs warmup then runs start_trigger
|
||||
// embench end with stop_trigger.
|
||||
//assign StartSampleFirst = FunctionName.FunctionName.FunctionName == "start_time";
|
||||
//assign StartSampleFirst = functionName.functionName.FunctionName == "start_time";
|
||||
//flopr #(1) StartSampleReg(clk, reset, StartSampleFirst, StartSampleDelayed);
|
||||
//assign StartSample = StartSampleFirst & ~ StartSampleDelayed;
|
||||
|
||||
//assign EndSampleFirst = FunctionName.FunctionName.FunctionName == "stop_time";
|
||||
//assign EndSampleFirst = functionName.functionName.FunctionName == "stop_time";
|
||||
flopr #(1) EndSampleReg(clk, reset, EndSampleFirst, EndSampleDelayed);
|
||||
assign EndSample = EndSampleFirst & ~ EndSampleDelayed;
|
||||
|
||||
|
@ -1,12 +1,14 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import sys, fileinput
|
||||
import sys
|
||||
import fileinput
|
||||
|
||||
address = 0
|
||||
|
||||
|
||||
for line in fileinput.input('-'):
|
||||
with fileinput.input('-') as f:
|
||||
for line in f:
|
||||
# the 14- is to reverse the byte order to little endian
|
||||
formatedLine = ' '.join(line[14-i:14-i+2] for i in range(0, len(line), 2))
|
||||
sys.stdout.write('@{:08x} {:s}\n'.format(address, formatedLine))
|
||||
sys.stdout.write(f'@{address:08x} {formatedLine:s}\n')
|
||||
address+=8
|
||||
|
@ -684,8 +684,8 @@ module testbench;
|
||||
loggers (clk, reset, DCacheFlushStart, DCacheFlushDone, memfilename, TEST);
|
||||
|
||||
// track the current function or global label
|
||||
if (DEBUG > 0 | ((PrintHPMCounters | BPRED_LOGGER) & P.ZICNTR_SUPPORTED)) begin : FunctionName
|
||||
FunctionName #(P) FunctionName(.reset(reset_ext | TestBenchReset),
|
||||
if (DEBUG > 0 | ((PrintHPMCounters | BPRED_LOGGER) & P.ZICNTR_SUPPORTED)) begin : functionName
|
||||
functionName #(P) functionName(.reset(reset_ext | TestBenchReset),
|
||||
.clk(clk), .ProgramAddrMapFile(ProgramAddrMapFile), .ProgramLabelMapFile(ProgramLabelMapFile));
|
||||
end
|
||||
|
||||
@ -710,11 +710,11 @@ module testbench;
|
||||
|
||||
always @(posedge clk) begin
|
||||
// if (reset) PrevPCZero <= 0;
|
||||
// else if (dut.core.InstrValidM) PrevPCZero <= (FunctionName.PCM == 0 & dut.core.ifu.InstrM == 0);
|
||||
// else if (dut.core.InstrValidM) PrevPCZero <= (functionName.PCM == 0 & dut.core.ifu.InstrM == 0);
|
||||
TestComplete <= ((InstrM == 32'h6f) & dut.core.InstrValidM ) |
|
||||
((dut.core.lsu.IEUAdrM == ProgramAddrLabelArray["tohost"] & dut.core.lsu.IEUAdrM != 0) & InstrMName == "SW"); // |
|
||||
// (FunctionName.PCM == 0 & dut.core.ifu.InstrM == 0 & dut.core.InstrValidM & PrevPCZero));
|
||||
// if (FunctionName.PCM == 0 & dut.core.ifu.InstrM == 0 & dut.core.InstrValidM & PrevPCZero)
|
||||
// (functionName.PCM == 0 & dut.core.ifu.InstrM == 0 & dut.core.InstrValidM & PrevPCZero));
|
||||
// if (functionName.PCM == 0 & dut.core.ifu.InstrM == 0 & dut.core.InstrValidM & PrevPCZero)
|
||||
// $error("Program fetched illegal instruction 0x00000000 from address 0x00000000 twice in a row. Usually due to fault with no fault handler.");
|
||||
end
|
||||
|
||||
|
@ -40,9 +40,9 @@ mem_addr = mem_start_addr
|
||||
|
||||
def wl(line="", comment=None, fname=test_name):
|
||||
with open(fname, "a") as f:
|
||||
instr = False if (":" in line or
|
||||
instr = not (":" in line or
|
||||
".align" in line or
|
||||
"# include" in line) else True
|
||||
"# include" in line)
|
||||
indent = 6 if instr else 0
|
||||
comment = "// " + comment if comment is not None else ""
|
||||
to_write = " " * indent + line + comment + "\n"
|
||||
@ -78,7 +78,7 @@ if __name__ == "__main__":
|
||||
for i in range(dcache_num_ways):
|
||||
wl(comment=f"start way test #{i+1}")
|
||||
wl(f'li t0, {hex(mem_addr)}')
|
||||
wl(f'.align 6') # start at i$ set boundary. 6 lsb bits are zero.
|
||||
wl('.align 6') # start at i$ set boundary. 6 lsb bits are zero.
|
||||
wl(comment=f"i$ boundary, way test #{i+1}")
|
||||
write_repro_instrs()
|
||||
mem_addr += dcache_way_size_in_bytes # so that we excercise a new D$ way.
|
||||
|
@ -60,9 +60,9 @@ class Config:
|
||||
def create_vectors(my_config):
|
||||
suite_folder_num = my_config.bits
|
||||
if my_config.bits == 64 and my_config.letter == "F": suite_folder_num = 32
|
||||
source_dir1 = "{}/addins/riscv-arch-test/riscv-test-suite/rv{}i_m/{}/src/".format(wally, suite_folder_num, my_config.letter)
|
||||
source_dir2 = "{}/tests/riscof/work/riscv-arch-test/rv{}i_m/{}/src/".format(wally, my_config.bits, my_config.letter)
|
||||
dest_dir = "{}/tests/fp/combined_IF_vectors/IF_vectors/".format(wally)
|
||||
source_dir1 = f"{wally}/addins/riscv-arch-test/riscv-test-suite/rv{suite_folder_num}i_m/{my_config.letter}/src/"
|
||||
source_dir2 = f"{wally}/tests/riscof/work/riscv-arch-test/rv{my_config.bits}i_m/{my_config.letter}/src/"
|
||||
dest_dir = f"{wally}/tests/fp/combined_IF_vectors/IF_vectors/"
|
||||
all_vectors1 = os.listdir(source_dir1)
|
||||
|
||||
filt_vectors1 = [v for v in all_vectors1 if my_config.filt in v]
|
||||
@ -76,11 +76,8 @@ def create_vectors(my_config):
|
||||
operation = my_config.op_code
|
||||
rounding_mode = "X"
|
||||
flags = "XX"
|
||||
# use name to create our new tv
|
||||
dest_file = open("{}cvw_{}_{}.tv".format(dest_dir, my_config.bits, vector1[:-2]), 'w')
|
||||
# open vectors
|
||||
src_file1 = open(source_dir1 + vector1,'r')
|
||||
src_file2 = open(source_dir2 + vector2,'r')
|
||||
# use name to create our new tv and open vectors
|
||||
with open(f"{dest_dir}cvw_{my_config.bits}_{vector1[:-2]}.tv", 'w') as dest_file, open(source_dir1 + vector1) as src_file1, open(source_dir2 + vector2) as src_file2:
|
||||
# for each test in the vector
|
||||
reading = True
|
||||
src_file2.readline() #skip first bc junk
|
||||
@ -133,7 +130,7 @@ def create_vectors(my_config):
|
||||
done = True
|
||||
# put it all together
|
||||
if not done:
|
||||
translation = "{}_{}_{}_{}_{}_{}".format(operation, ext_bits(op1val), ext_bits(op2val), ext_bits(answer.strip()), flags, rounding_mode)
|
||||
translation = f"{operation}_{ext_bits(op1val)}_{ext_bits(op2val)}_{ext_bits(answer.strip())}_{flags}_{rounding_mode}"
|
||||
dest_file.write(translation + "\n")
|
||||
else:
|
||||
# print("read false")
|
||||
@ -182,7 +179,7 @@ def create_vectors(my_config):
|
||||
flags = "XX"
|
||||
# put it all together
|
||||
if not done:
|
||||
translation = "{}_{}_{}_{}_{}_{}".format(operation, ext_bits(op1val), ext_bits(op2val), ext_bits(answer.strip()), flags.strip(), rounding_mode)
|
||||
translation = f"{operation}_{ext_bits(op1val)}_{ext_bits(op2val)}_{ext_bits(answer.strip())}_{flags.strip()}_{rounding_mode}"
|
||||
dest_file.write(translation + "\n")
|
||||
else:
|
||||
# print("read false")
|
||||
@ -196,7 +193,7 @@ def create_vectors(my_config):
|
||||
answer = src_file2.readline().strip()
|
||||
# print(f"Answer: {answer}")
|
||||
#print(answer1,answer2)
|
||||
if not (answer == "6f5ca309"): # if there is still stuff to read
|
||||
if answer != '6f5ca309': # if there is still stuff to read
|
||||
# parse through .S file
|
||||
detected = False
|
||||
done = False
|
||||
@ -230,7 +227,7 @@ def create_vectors(my_config):
|
||||
flags = "XX"
|
||||
# put it all together
|
||||
if not done:
|
||||
translation = "{}_{}_{}_{}_{}_{}".format(operation, ext_bits(op1val), ext_bits(op2val), ext_bits(answer.strip()), flags.strip(), rounding_mode)
|
||||
translation = f"{operation}_{ext_bits(op1val)}_{ext_bits(op2val)}_{ext_bits(answer.strip())}_{flags.strip()}_{rounding_mode}"
|
||||
dest_file.write(translation + "\n")
|
||||
else:
|
||||
# print("read false")
|
||||
@ -279,15 +276,12 @@ def create_vectors(my_config):
|
||||
|
||||
# put it all together
|
||||
if not done:
|
||||
translation = "{}_{}_{}_{}_{}_{}".format(operation, ext_bits(op1val), ext_bits(op2val), ext_bits(answer.strip()), flags, rounding_mode)
|
||||
translation = f"{operation}_{ext_bits(op1val)}_{ext_bits(op2val)}_{ext_bits(answer.strip())}_{flags}_{rounding_mode}"
|
||||
dest_file.write(translation + "\n")
|
||||
else:
|
||||
# print("read false")
|
||||
reading = False
|
||||
# print("out")
|
||||
dest_file.close()
|
||||
src_file1.close()
|
||||
src_file2.close()
|
||||
|
||||
config_list = [
|
||||
Config(32, "M", "div", "div-", 0),
|
||||
|
@ -27,8 +27,8 @@ round_dict = {
|
||||
|
||||
print("creating testfloat div test vectors")
|
||||
|
||||
source_dir = "{}/tests/fp/vectors/".format(wally)
|
||||
dest_dir = "{}/tests/fp/combined_IF_vectors/IF_vectors/".format(wally)
|
||||
source_dir = f"{wally}/tests/fp/vectors/"
|
||||
dest_dir = f"{wally}/tests/fp/combined_IF_vectors/IF_vectors/"
|
||||
all_vectors = os.listdir(source_dir)
|
||||
|
||||
div_vectors = [v for v in all_vectors if "div" in v]
|
||||
@ -39,19 +39,15 @@ for vector in div_vectors:
|
||||
config_list = vector.split(".")[0].split("_")
|
||||
operation = "1" #float div
|
||||
rounding_mode = round_dict[str(config_list[2])]
|
||||
# use name to create our new tv
|
||||
dest_file = open(dest_dir + "cvw_" + vector, 'a')
|
||||
# open vector
|
||||
src_file = open(source_dir + vector,'r')
|
||||
# use name to create our new tv and open vector
|
||||
with open(dest_dir + "cvw_" + vector, 'a') as dest_file, open(source_dir + vector) as src_file:
|
||||
# for each test in the vector
|
||||
for i in src_file.readlines():
|
||||
translation = "" # this stores the test that we are currently working on
|
||||
[input_1, input_2, answer, flags] = i.split("_") # separate inputs, answer, and flags
|
||||
# put it all together, strip nec for removing \n on the end of the flags
|
||||
translation = "{}_{}_{}_{}_{}_{}".format(operation, ext_bits(input_1), ext_bits(input_2), ext_bits(answer), flags.strip(), rounding_mode)
|
||||
translation = f"{operation}_{ext_bits(input_1)}_{ext_bits(input_2)}_{ext_bits(answer)}_{flags.strip()}_{rounding_mode}"
|
||||
dest_file.write(translation + "\n")
|
||||
dest_file.close()
|
||||
src_file.close()
|
||||
|
||||
|
||||
print("creating testfloat sqrt test vectors")
|
||||
@ -64,10 +60,8 @@ for vector in sqrt_vectors:
|
||||
config_list = vector.split(".")[0].split("_")
|
||||
operation = "2" #sqrt
|
||||
rounding_mode = round_dict[str(config_list[2])]
|
||||
# use name to create our new tv
|
||||
dest_file = open(dest_dir + "cvw_" + vector, 'a')
|
||||
# open vector
|
||||
src_file = open(source_dir + vector,'r')
|
||||
# use name to create our new tv and open vector
|
||||
with open(dest_dir + "cvw_" + vector, 'a') as dest_file, open(source_dir + vector) as src_file:
|
||||
# for each test in the vector
|
||||
for i in src_file.readlines():
|
||||
translation = "" # this stores the test that we are currently working on
|
||||
@ -75,5 +69,3 @@ for vector in sqrt_vectors:
|
||||
# put it all together, strip nec for removing \n on the end of the flags
|
||||
translation = "{}_{}_{}_{}_{}_{}".format(operation, ext_bits(input_1), "X"*32, ext_bits(answer), flags.strip(), rounding_mode)
|
||||
dest_file.write(translation + "\n")
|
||||
dest_file.close()
|
||||
src_file.close()
|
@ -1,17 +1,10 @@
|
||||
import os
|
||||
import re
|
||||
import shutil
|
||||
import subprocess
|
||||
import shlex
|
||||
import logging
|
||||
import random
|
||||
import string
|
||||
from string import Template
|
||||
|
||||
import riscof.utils as utils
|
||||
from riscof.pluginTemplate import pluginTemplate
|
||||
import riscof.constants as constants
|
||||
from riscv_isac.isac import isac
|
||||
|
||||
logger = logging.getLogger()
|
||||
|
||||
@ -72,11 +65,11 @@ class sail_cSim(pluginTemplate):
|
||||
self.sailargs += "--enable-zcb"
|
||||
if "Q" in ispec["ISA"]:
|
||||
self.isa += 'q'
|
||||
objdump = "riscv64-unknown-elf-objdump".format(self.xlen)
|
||||
objdump = "riscv64-unknown-elf-objdump"
|
||||
if shutil.which(objdump) is None:
|
||||
logger.error(objdump+": executable not found. Please check environment setup.")
|
||||
raise SystemExit(1)
|
||||
compiler = "riscv64-unknown-elf-gcc".format(self.xlen)
|
||||
compiler = "riscv64-unknown-elf-gcc"
|
||||
if shutil.which(compiler) is None:
|
||||
logger.error(compiler+": executable not found. Please check environment setup.")
|
||||
raise SystemExit(1)
|
||||
@ -114,9 +107,9 @@ class sail_cSim(pluginTemplate):
|
||||
if ('NO_SAIL=True' in testentry['macros']):
|
||||
# if the tests can't run on SAIL we copy the reference output to the src directory
|
||||
reference_output = re.sub("/src/","/references/", re.sub(".S",".reference_output", test))
|
||||
execute += 'cut -c-{0:g} {1} > {2}'.format(8, reference_output, sig_file) #use cut to remove comments when copying
|
||||
execute += f'cut -c-{8:g} {reference_output} > {sig_file}' #use cut to remove comments when copying
|
||||
else:
|
||||
execute += self.sail_exe[self.xlen] + ' -z268435455 -i --trace=step ' + self.sailargs + ' --test-signature={0} {1} > {2}.log 2>&1;'.format(sig_file, elf, test_name)
|
||||
execute += self.sail_exe[self.xlen] + ' -z268435455 -i --trace=step ' + self.sailargs + f' --test-signature={sig_file} {elf} > {test_name}.log 2>&1;'
|
||||
|
||||
cov_str = ' '
|
||||
for label in testentry['coverage_labels']:
|
||||
@ -124,10 +117,10 @@ class sail_cSim(pluginTemplate):
|
||||
|
||||
if cgf_file is not None:
|
||||
coverage_cmd = 'riscv_isac --verbose info coverage -d \
|
||||
-t {0}.log --parser-name c_sail -o coverage.rpt \
|
||||
-t {}.log --parser-name c_sail -o coverage.rpt \
|
||||
--sig-label begin_signature end_signature \
|
||||
--test-label rvtest_code_begin rvtest_code_end \
|
||||
-e ref.elf -c {1} -x{2} {3};'.format(\
|
||||
-e ref.elf -c {} -x{} {};'.format(\
|
||||
test_name, ' -c '.join(cgf_file), self.xlen, cov_str)
|
||||
else:
|
||||
coverage_cmd = ''
|
||||
|
@ -1,16 +1,8 @@
|
||||
import os
|
||||
import re
|
||||
import shutil
|
||||
import subprocess
|
||||
import shlex
|
||||
import logging
|
||||
import random
|
||||
import string
|
||||
from string import Template
|
||||
import sys
|
||||
|
||||
import riscof.utils as utils
|
||||
import riscof.constants as constants
|
||||
from riscof.pluginTemplate import pluginTemplate
|
||||
|
||||
logger = logging.getLogger()
|
||||
@ -202,14 +194,14 @@ class spike(pluginTemplate):
|
||||
if ('NO_SAIL=True' in testentry['macros']):
|
||||
# if the tests can't run on SAIL we copy the reference output to the src directory
|
||||
reference_output = re.sub("/src/","/references/", re.sub(".S",".reference_output", test))
|
||||
simcmd = 'cut -c-{0:g} {1} > {2}'.format(8, reference_output, sig_file) #use cut to remove comments when copying
|
||||
simcmd = f'cut -c-{8:g} {reference_output} > {sig_file}' #use cut to remove comments when copying
|
||||
else:
|
||||
simcmd = self.dut_exe + ' --isa={0} +signature={1} +signature-granularity=4 {2}'.format(self.isa, sig_file, elf)
|
||||
simcmd = self.dut_exe + f' --isa={self.isa} +signature={sig_file} +signature-granularity=4 {elf}'
|
||||
else:
|
||||
simcmd = 'echo "NO RUN"'
|
||||
|
||||
# concatenate all commands that need to be executed within a make-target.
|
||||
execute = '@cd {0}; {1}; {2};'.format(testentry['work_dir'], cmd, simcmd)
|
||||
execute = '@cd {}; {}; {};'.format(testentry['work_dir'], cmd, simcmd)
|
||||
|
||||
# create a target. The makeutil will create a target with the name "TARGET<num>" where num
|
||||
# starts from 0 and increments automatically for each new target that is added
|
||||
|
@ -17,7 +17,7 @@ if __name__ == "__main__":
|
||||
line_num = int(sig_adr / 4) + 1
|
||||
offset = sig_adr & 0x3F
|
||||
test_num = int((sig_adr-offset)/int("40",16))
|
||||
print("IntrNum 0x{:02X}".format(test_num))
|
||||
print("Offset 0x{:02X}".format(offset))
|
||||
print(f"IntrNum 0x{test_num:02X}")
|
||||
print(f"Offset 0x{offset:02X}")
|
||||
print("LineNum "+str(line_num))
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user