Skip to content

Commit

Permalink
Merge pull request #74 from efabless/dev
Browse files Browse the repository at this point in the history
hash netlist to recompile if it changes
  • Loading branch information
M0stafaRady authored Dec 9, 2024
2 parents 186562e + 66cad75 commit 5bb555a
Show file tree
Hide file tree
Showing 5 changed files with 65 additions and 22 deletions.
2 changes: 1 addition & 1 deletion cocotb/caravel_cocotb/CI/setup_env.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ def clone_needed_repos(self):
depth=1,
branch="main",
)
self.download_sky130_pdk("e3b630d9b7c0e23615367d52c4f78b2d2ede58ac")
self.download_sky130_pdk("a918dc7c8e474a99b68c85eb3546b4ed91fe9e7b")

def pull_cocotb_docker(self):
image_name = "efabless/dv"
Expand Down
8 changes: 2 additions & 6 deletions cocotb/caravel_cocotb/caravel_interfaces.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
from caravel_cocotb.interfaces.caravel import Caravel_env # noqa: F401
from caravel_cocotb.interfaces.SPI import SPI # noqa: F401
from caravel_cocotb.interfaces.UART import UART # noqa: F401
from caravel_cocotb.interfaces.common_functions.test_functions import (
test_configure,
) # noqa: F401
from caravel_cocotb.interfaces.common_functions.test_functions import (
report_test,
) # noqa: F401
from caravel_cocotb.interfaces.common_functions.test_functions import (test_configure) # noqa: F401
from caravel_cocotb.interfaces.common_functions.test_functions import (report_test) # noqa: F401
from caravel_cocotb.interfaces.common import GPIO_MODE # noqa: F401
8 changes: 0 additions & 8 deletions cocotb/caravel_cocotb/scripts/verify_cocotb/RunRegression.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
import smtplib
import socket
import yaml
import time
from caravel_cocotb.scripts.merge_coverage import merge_fun_cov
from caravel_cocotb.scripts.test_defaults.test_defaults import TestDefaults
from rich.live import Live
Expand Down Expand Up @@ -490,12 +489,6 @@ def unzip_sdf_files(self):
return
elif self.args.sim != "GL_SDF":
return
# make corners list in case in is n't
if not isinstance(self.args.corner, list):
corners = [self.args.corner]
else:
corners = self.args.corner

# keep caravel sdf dir
sdf_dir = f"{self.paths.CARAVEL_ROOT}/signoff/{'caravan' if self.args.caravan else 'caravel'}/primetime/sdf"
if self.args.sdfs_dir is None:
Expand All @@ -512,4 +505,3 @@ def unzip_sdf_files(self):
for gz_file in gz_files:
subprocess.run(f"gzip {gz_file} -d".split())
self.args.macros.append(f'SDF_PATH=\\"{sdf_dir}\\"')

65 changes: 58 additions & 7 deletions cocotb/caravel_cocotb/scripts/verify_cocotb/RunTest.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,12 @@
import re
import logging
import caravel_cocotb
import hashlib


class RunTest:
COMPILE_LOCK = set()

def __init__(self, args, paths, test, logger) -> None:
self.args = args
self.paths = paths
Expand Down Expand Up @@ -139,15 +142,23 @@ def runTest(self):
def runTest_iverilog(self):
if self.test.sim == "GL_SDF":
raise RuntimeError(
f"iverilog can't run SDF for test {self.test.name} Please use anothor simulator like cvc"
f"{bcolors.FAIL}iverilog can't run SDF for test {self.test.name} Please use anothor simulator like cvc{bcolors.ENDC}"
)
return
self.write_iverilog_includes_file()
if (
not os.path.isfile(f"{self.test.compilation_dir}/sim.vvp")
or self.args.compile
):
if not os.path.isfile(f"{self.test.compilation_dir}/sim.vvp"):
print(f"{bcolors.OKCYAN}Compiling as sim.vvp not found{bcolors.ENDC}")
self.iverilog_compile()
elif self.args.compile:
print(f"{bcolors.OKCYAN}Compiling as compile flag is set{bcolors.ENDC}")
self.iverilog_compile()
elif not self.is_same_hash(self.test.netlist) and f"{self.test.compilation_dir}/sim.vvp" not in RunTest.COMPILE_LOCK:
print(f"{bcolors.OKCYAN}Compiling since netlist has has changed{bcolors.ENDC}")
self.iverilog_compile()
else:
if f"{self.test.compilation_dir}/sim.vvp" not in RunTest.COMPILE_LOCK:
print(f"{bcolors.OKCYAN}Skipping compilation as netlist has not changed{bcolors.ENDC}")
RunTest.COMPILE_LOCK.add(f"{self.test.compilation_dir}/sim.vvp") # locked means if it is copiled for the first time then it will not be compiled again even if netlist changes
if not self.args.compile_only:
self.iverilog_run()

Expand Down Expand Up @@ -216,8 +227,19 @@ def runTest_vcs(self):
self.vcs_coverage_command = "-cm line+tgl+cond+fsm+branch+assert "
os.environ["TESTCASE"] = f"{self.test.name}"
os.environ["MODULE"] = "module_trail"
if not os.path.isfile(f"{self.test.compilation_dir}/simv") or self.args.compile:
if not os.path.isfile(f"{self.test.compilation_dir}/simv"):
print(f"{bcolors.OKCYAN}Compiling as simv not found{bcolors.ENDC}")
self.vcs_compile()
elif self.args.compile:
print(f"{bcolors.OKCYAN}Compiling as compile flag is set{bcolors.ENDC}")
self.vcs_compile()
elif not self.is_same_hash(self.test.netlist) and f"{self.test.compilation_dir}/simv" not in RunTest.COMPILE_LOCK:
print(f"{bcolors.OKCYAN}Compiling since netlist has has changed{bcolors.ENDC}")
self.vcs_compile()
else:
if f"{self.test.compilation_dir}/simv" not in RunTest.COMPILE_LOCK:
print(f"{bcolors.OKCYAN}Skipping compilation as netlist has not changed{bcolors.ENDC}")
RunTest.COMPILE_LOCK.add(f"{self.test.compilation_dir}/simv") # locked means if it is copiled for the first time then it will not be compiled again even if netlist changes
if not self.args.compile_only:
self.vcs_run()

Expand All @@ -241,7 +263,7 @@ def vcs_compile(self):
)
lint = "+lint=all" if self.args.lint else ""
ignored_errors = " -error=noZMMCM "
vcs_cmd = f"cd {self.test.compilation_dir}; vcs {lint} -negdelay {self.vcs_coverage_command} {ignored_errors}-debug_access+all +error+50 +vcs+loopreport+1000000 -diag=sdf:verbose +sdfverbose +neg_tchk -debug_access -full64 -l {self.test.compilation_dir}/test_compilation.log caravel_top -Mdir={self.test.compilation_dir}/csrc -o {self.test.compilation_dir}/simv +vpi -P pli.tab -load $(cocotb-config --lib-name-path vpi vcs)"
vcs_cmd = f"cd {self.test.compilation_dir}; vcs {lint} -negdelay {self.vcs_coverage_command} {ignored_errors} -debug_access+all +error+50 +vcs+loopreport+1000000 -diag=sdf:verbose +sdfverbose +neg_tchk -full64 -l {self.test.compilation_dir}/test_compilation.log caravel_top -Mdir={self.test.compilation_dir}/csrc -o {self.test.compilation_dir}/simv +vpi -P pli.tab -load $(cocotb-config --lib-name-path vpi vcs)"
self.run_command_write_to_file(
vcs_cmd,
self.test.compilation_log,
Expand Down Expand Up @@ -309,6 +331,35 @@ def run_command_write_to_file(self, cmd, file, logger, quiet=True):

return process.returncode

@staticmethod
def calculate_netlist_hash(netlist, hash_algorithm="sha256"):
"""Calculate a combined hash of multiple files ignoring the order."""
hash_func = getattr(hashlib, hash_algorithm)()
try:
for file_path in sorted(netlist): # Ensure consistent order
with open(file_path, "rb") as f:
while chunk := f.read(8192):
hash_func.update(chunk)
return hash_func.hexdigest()
except FileNotFoundError as e:
return f"File not found: {e.filename}"
except PermissionError as e:
return f"Permission denied: {e.filename}"

def is_same_hash(self, netlist):
# read old hash if exists
try:
with open(self.test.hash_log, "r") as f:
old_hash = f.read().strip()
except FileNotFoundError:
old_hash = 0
# calculate new hash
new_hash = self.calculate_netlist_hash(netlist)
# write new hash
with open(self.test.hash_log, "w") as f:
f.write(new_hash)
return new_hash == old_hash


class bcolors:
HEADER = "\033[95m"
Expand Down
4 changes: 4 additions & 0 deletions cocotb/caravel_cocotb/scripts/verify_cocotb/Test.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ def __init__(self, name, sim, corner, args, paths, logger, local_macros=None):
)
self.include_dirs = set()
self.init_test()
self.netlist = set()

def init_test(self):
self.start_time = "-"
Expand Down Expand Up @@ -148,6 +149,7 @@ def create_logs(self):
# self.test_log=open(test_log, "w")
self.compilation_log = f"{self.compilation_dir}/compilation.log"
self.hex_log = f"{self.test_dir}/firmware.log"
self.hash_log = f"{self.compilation_dir}/hash.txt"
# self.full_terminal = open(self.compilation_log, "w")

def create_lint_log(self):
Expand Down Expand Up @@ -337,8 +339,10 @@ def convert_list_to_include(self, file):
if "*" in file_path:
for wild_match in glob.glob(file_path):
paths += f'`include "{wild_match}"\n'
self.netlist.add(wild_match)
else:
paths += f'`include "{file_path}"\n'
self.netlist.add(file_path)
# Add Includes to Set
include_indices = [
i for i, flag in enumerate(split_line) if flag == "-I"
Expand Down

0 comments on commit 5bb555a

Please sign in to comment.