cocotb - update verify_cocotb.py script to fully support running with iverilog in RTL and GL mode

This commit is contained in:
M0stafaRady 2022-10-20 06:28:07 -07:00
parent 98d089ed08
commit af9110c6dd
2 changed files with 81 additions and 112 deletions

View File

@ -1,79 +0,0 @@
# SPDX-FileCopyrightText: 2020 Efabless Corporation
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# 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.
#
# SPDX-License-Identifier: Apache-2.0
PWDD := $(shell pwd)
BLOCKS := $(shell basename $(PWDD))
# ---- Include Partitioned Makefiles ----
CONFIG = caravel_user_project
# TestName = temp_partial
# export COCOTB_ANSI_OUTPUT=0 # disable color in termianl
export GUI=1
export COCOTB_REDUCED_LOG_FMT=1
# Change this line if you want to use existing cocotb test modules:
# export PYTHONPATH := $(DESIGNS)/verilog/rtl/<your design python tests>
# export LIBPYTHON_LOC=$(cocotb-config --libpython)
#export VERILOG_PATH = ../../../
#export CARAVEL_PATH = ../../../../../caravel/verilog/
# include $(MCW_ROOT)/verilog/dv/make/env.makefile
# #export VERILOG_PATH = ../../../
# include $(MCW_ROOT)/verilog/dv/make/var.makefile
# include $(MCW_ROOT)/verilog/dv/make/cpu.makefile
# include $(MCW_ROOT)/verilog/dv/make/sim.makefile
TESTCASE=$(TestName)
MODULE=caravel_tests
$(info $$MODULE is [$(MODULE)])
cocotb:
rm -rf sim_build/
mkdir sim_build/
# change project_tb.v to match your testbench
#RTL
iverilog -Ttyp -DFUNCTIONAL -DSIM -DUSE_POWER_PINS -DUNIT_DELAY=#1 \
-DTESTNAME=\"$(TestName)\" -DTAG=\"$(RUNTAG)\" -DSIM=\"$(SIM)\" \
-f$(VERILOG_PATH)/includes/includes.rtl.caravel \
-o sim_build/sim.vvp $(CARAVEL_PATH)/rtl/__user_project_wrapper.v $(CARAVEL_PATH)/rtl/debug_regs.v caravel_top.sv
#GL
# iverilog -Ttyp -DFUNCTIONAL -DGL -DUSE_POWER_PINS -DUNIT_DELAY=#1 \
# -DTESTNAME=\"$(TestName)\" -DRUNTAG=\"$(RUNTAG)\" -DSIM=\"$(SIM)\" \
# -f$(VERILOG_PATH)/includes/includes.gl.caravel \
# -f$(USER_PROJECT_VERILOG)/includes/includes.gl.$(CONFIG) -o sim_build/sim.vvp caravel_top.sv
#CVC
# TESTCASE=$(TestName) MODULE=caravel_tests cvc64 +interp +acc+2 \
# +loadvpi=$(shell cocotb-config --lib-name-path vpi cvc):vlog_startup_routines_bootstrap\
# +change_port_type +maxerrors 1\
# +define+SIM +define+FUNCTIONAL +define+GL +define+USE_POWER_PINS +define+UNIT_DELAY=#0 \
# +define+TESTNAME=\"$(TestName)\" +define+RUNTAG=\"$(RUNTAG)\" +define+COCOTB_SIM=1\
# -f $(VERILOG_PATH)/includes/includes.gl+sdf.caravel \
# -f $(USER_PROJECT_VERILOG)/includes/includes.gl+sdf.$(CONFIG) -o sim_build/sim.vvp
# verilator --vpi --public-flat-rw --prefix Vtop \
# -LDFLAGS "-Wl,-rpath,$(cocotb-config --prefix)/cocotb/libs \
# -L$(cocotb-config --prefix)/cocotb/libs \
# -lcocotbvpi_verilator -lgpi -lcocotb -lgpilog -lcocotbutils" \
# $(cocotb-config --share)/lib/verilator/verilator.cpp\
# -y $(VERILOG_PATH)/includes/includes.rtl.caravel \
# -y $(USER_PROJECT_VERILOG)/includes/includes.rtl.$(CONFIG) --cc -o sim_build/sim.vvp caravel_top.sv
# change this line to choose the comma separated test cases and the name of your python test module
TESTCASE=$(TestName) MODULE=caravel_tests vvp -M $$(cocotb-config --prefix)/cocotb/libs -m libcocotbvpi_icarus sim_build/sim.vvp
! grep failure results.xml

View File

@ -12,7 +12,8 @@ import random
from pathlib import Path from pathlib import Path
import shutil import shutil
from subprocess import PIPE, run from subprocess import PIPE, run
import threading
import time
iverilog = True iverilog = True
vcs = False vcs = False
@ -67,14 +68,21 @@ class RunTest:
self.sim_path = f"sim/{os.getenv('RUNTAG')}/{test_dir}/" self.sim_path = f"sim/{os.getenv('RUNTAG')}/{test_dir}/"
terminal_log=f"{self.sim_path}/fullTerminal.log" terminal_log=f"{self.sim_path}/fullTerminal.log"
test_log=f"{self.sim_path}/{self.test_name}.log" test_log=f"{self.sim_path}/{self.test_name}.log"
self.full_terminal = open(test_log, "w") self.test_log=open(test_log, "w")
self.full_file=f"{self.sim_path}/full.log"
self.full_terminal = open(self.full_file, "w")
def runTest(self): def runTest(self):
self.full_test_name = f"{self.sim_type}-{self.test_name}"
if (self.sim_type=="GL_SDF"):
self.full_test_name = f"{self.sim_type}-{self.test_name}-{self.corner}"
os.environ["TESTFULLNAME"] = f"{self.full_test_name}"
if (iverilog):return self.runTest_iverilog() if (iverilog):return self.runTest_iverilog()
elif(vcs): return self.runTest_vcs() elif(vcs): return self.runTest_vcs()
# iverilog function # iverilog function
def runTest_iverilog(self): def runTest_iverilog(self):
print(f"Start running test: {self.sim_type}-{self.test_name}")
CARAVEL_ROOT = os.getenv('CARAVEL_ROOT') CARAVEL_ROOT = os.getenv('CARAVEL_ROOT')
CARAVEL_VERILOG_PATH = os.getenv('CARAVEL_VERILOG_PATH') CARAVEL_VERILOG_PATH = os.getenv('CARAVEL_VERILOG_PATH')
MCW_ROOT = os.getenv('MCW_ROOT') MCW_ROOT = os.getenv('MCW_ROOT')
@ -86,12 +94,39 @@ class RunTest:
ERRORMAX = os.getenv('ERRORMAX') ERRORMAX = os.getenv('ERRORMAX')
PDK_ROOT = os.getenv('PDK_ROOT') PDK_ROOT = os.getenv('PDK_ROOT')
PDK = os.getenv('PDK') PDK = os.getenv('PDK')
env_vars = f"-e {CARAVEL_ROOT} -e CARAVEL_VERILOG_PATH={CARAVEL_VERILOG_PATH} -e MCW_ROOT={MCW_ROOT} -e VERILOG_PATH={VERILOG_PATH} -e CARAVEL_PATH={CARAVEL_PATH} -e USER_PROJECT_VERILOG={USER_PROJECT_VERILOG} -e FIRMWARE_PATH={FIRMWARE_PATH} -e RUNTAG={RUNTAG} -e ERRORMAX={ERRORMAX} -e PDK_ROOT={PDK_ROOT} -e PDK={PDK}" TESTFULLNAME = os.getenv('TESTFULLNAME')
print(f"Start running test: {self.sim_type}-{self.test_name}") env_vars = f"-e {CARAVEL_ROOT} -e CARAVEL_VERILOG_PATH={CARAVEL_VERILOG_PATH} -e MCW_ROOT={MCW_ROOT} -e VERILOG_PATH={VERILOG_PATH} -e CARAVEL_PATH={CARAVEL_PATH} -e USER_PROJECT_VERILOG={USER_PROJECT_VERILOG} -e FIRMWARE_PATH={FIRMWARE_PATH} -e RUNTAG={RUNTAG} -e ERRORMAX={ERRORMAX} -e PDK_ROOT={PDK_ROOT} -e PDK={PDK} -e TESTFULLNAME={TESTFULLNAME}"
command = f"TestName={self.test_name} SIM={self.sim_type} make cocotb >> {self.full_terminal.name} " macros = f'-DFUNCTIONAL -DSIM=\\\"{self.sim_type}\\\" -DUSE_POWER_PINS -DUNIT_DELAY=#1 -DMAIN_PATH=\\\"{self.cocotb_path}\\\" -DIVERILOG -DTESTNAME=\\\"{self.test_name}\\\" -DTAG=\\\"{RUNTAG}\\\" '
os.system(f"docker run -it {env_vars} -v {os.getenv('CARAVEL_ROOT')}:{os.getenv('CARAVEL_ROOT')} -v {os.getenv('MCW_ROOT')}:{os.getenv('MCW_ROOT')} -v {os.getenv('PDK_ROOT')}:{os.getenv('PDK_ROOT')} efabless/dv:cocotb sh -c 'cd {self.cocotb_path} && {command}'") if self.test_name == "la":
self.passed = search_str(self.full_terminal.name,"Test passed with (0)criticals (0)errors") macros = f'{macros} -DLA_TESTING'
if self.test_name in ["gpio_all_o_user","gpio_all_i_user","gpio_all_i_pu_user","gpio_all_i_pd_user","gpio_all_bidir_user"]:
macros = f'{macros} -DGPIO_TESTING'
if(self.sim_type=="RTL"):
includes = f"-f {VERILOG_PATH}/includes/includes.rtl.caravel"
elif(self.sim_type=="GL"):
macros = f'{macros} -DGL'
includes = f"-f {VERILOG_PATH}/includes/includes.gl.caravel"
elif(self.sim_type=="GLSDF"):
print(f"iverilog can't run SDF for test {self.test_name} Please use anothor simulator like cvc" )
return
iverilog_command = (f"iverilog -Ttyp {macros} {includes} -o {self.sim_path}/sim.vvp"
f" {CARAVEL_PATH}/rtl/__user_project_wrapper.v {CARAVEL_PATH}/rtl/__user_project_gpio_example.v {CARAVEL_PATH}/rtl/__user_project_la_example.v caravel_top.sv"
f" && TESTCASE={self.test_name} MODULE=caravel_tests vvp -M $(cocotb-config --prefix)/cocotb/libs -m libcocotbvpi_icarus {self.sim_path}/sim.vvp")
docker_command = f"docker run -it {env_vars} -v {os.getenv('CARAVEL_ROOT')}:{os.getenv('CARAVEL_ROOT')} -v {os.getenv('MCW_ROOT')}:{os.getenv('MCW_ROOT')} -v {os.getenv('PDK_ROOT')}:{os.getenv('PDK_ROOT')} efabless/dv:cocotb sh -c 'cd {self.cocotb_path} && {iverilog_command}' >> {self.full_file}"
self.full_terminal = open(self.full_file, "a")
self.full_terminal.write(f"docker command for running iverilog and cocotb:\n% ")
self.full_terminal.write(os.path.expandvars(docker_command)+"\n")
self.full_terminal.close()
os.system(docker_command)
self.passed = search_str(self.test_log.name,"Test passed with (0)criticals (0)errors")
Path(f'{self.sim_path}/{self.passed}').touch() Path(f'{self.sim_path}/{self.passed}').touch()
if self.passed == "passed":
print(f"Test: {self.sim_type}-{self.test_name} passed")
else :
print(f"Test: {self.sim_type}-{self.test_name} Failed please check logs under {self.sim_path}")
# vcs function # vcs function
def runTest_vcs(self): def runTest_vcs(self):
@ -104,7 +139,6 @@ class RunTest:
dirs = f' {dirs} -f \\\"{VERILOG_PATH}/includes/rtl_caravel_vcs.list\\\" ' dirs = f' {dirs} -f \\\"{VERILOG_PATH}/includes/rtl_caravel_vcs.list\\\" '
else: else:
dirs = f' {dirs} -f \\\"{VERILOG_PATH}/includes/gl_caravel_vcs.list\\\" ' dirs = f' {dirs} -f \\\"{VERILOG_PATH}/includes/gl_caravel_vcs.list\\\" '
full_test_name = f"{self.sim_type}-{self.test_name}"
macros = f'+define+FUNCTIONAL +define+USE_POWER_PINS +define+UNIT_DELAY=#1 +define+MAIN_PATH=\\\"{self.cocotb_path}\\\" +define+VCS ' macros = f'+define+FUNCTIONAL +define+USE_POWER_PINS +define+UNIT_DELAY=#1 +define+MAIN_PATH=\\\"{self.cocotb_path}\\\" +define+VCS '
if self.test_name == "la": if self.test_name == "la":
macros = f'{macros} +define+LA_TESTING' macros = f'{macros} +define+LA_TESTING'
@ -119,7 +153,6 @@ class RunTest:
# os.makedirs(f"annotation_logs",exist_ok=True) # os.makedirs(f"annotation_logs",exist_ok=True)
dirs = f"{dirs} +incdir+\\\"{os.getenv('MCW_ROOT')}/verilog/\\\" " dirs = f"{dirs} +incdir+\\\"{os.getenv('MCW_ROOT')}/verilog/\\\" "
# +incdir+\\\"{os.getenv('CARAVEL_ROOT')}/signoff/caravel/primetime-signoff/\\\" # +incdir+\\\"{os.getenv('CARAVEL_ROOT')}/signoff/caravel/primetime-signoff/\\\"
full_test_name = f"{self.sim_type}-{self.test_name}-{self.corner}"
elif(self.sim_type=="GL"): elif(self.sim_type=="GL"):
macros = f'{macros} +define+GL +define+SIM=GL' macros = f'{macros} +define+GL +define+SIM=GL'
elif (self.sim_type=="RTL"): elif (self.sim_type=="RTL"):
@ -132,11 +165,10 @@ class RunTest:
os.environ["TESTCASE"] = f"{self.test_name}" os.environ["TESTCASE"] = f"{self.test_name}"
os.environ["MODULE"] = f"caravel_tests" os.environ["MODULE"] = f"caravel_tests"
os.environ["SIM"] = self.sim_type os.environ["SIM"] = self.sim_type
os.environ["TESTFULLNAME"] = f"{full_test_name}"
os.system(f"vlogan -full64 -sverilog +error+30 caravel_top.sv {dirs} {macros} +define+TESTNAME=\\\"{self.test_name}\\\" +define+FTESTNAME=\\\"{full_test_name}\\\" +define+TAG=\\\"{os.getenv('RUNTAG')}\\\" -l {self.sim_path}/analysis.log -o {self.sim_path} ") os.system(f"vlogan -full64 -sverilog +error+30 caravel_top.sv {dirs} {macros} +define+TESTNAME=\\\"{self.test_name}\\\" +define+FTESTNAME=\\\"{self.full_test_name}\\\" +define+TAG=\\\"{os.getenv('RUNTAG')}\\\" -l {self.sim_path}/analysis.log -o {self.sim_path} ")
os.system(f"vcs +lint=TFIPC-L {coverage_command} +error+30 -R -diag=sdf:verbose +sdfverbose +neg_tchk -debug_access -full64 -l {self.sim_path}/test.log caravel_top -Mdir={self.sim_path}/csrc -o {self.sim_path}/simv +vpi -P pli.tab -load $(cocotb-config --lib-name-path vpi vcs)") os.system(f"vcs +lint=TFIPC-L {coverage_command} +error+30 -R -diag=sdf:verbose +sdfverbose +neg_tchk -debug_access -full64 -l {self.sim_path}/test.log caravel_top -Mdir={self.sim_path}/csrc -o {self.sim_path}/simv +vpi -P pli.tab -load $(cocotb-config --lib-name-path vpi vcs)")
self.passed = search_str(self.full_terminal.name,"Test passed with (0)criticals (0)errors") self.passed = search_str(self.test_log.name,"Test passed with (0)criticals (0)errors")
Path(f'{self.sim_path}/{self.passed}').touch() Path(f'{self.sim_path}/{self.passed}').touch()
#delete wave when passed #delete wave when passed
if self.passed == "passed" and zip_waves: if self.passed == "passed" and zip_waves:
@ -192,9 +224,11 @@ class RunTest:
sed_command = f"sed -ie 's/@10/@00/g' {hex_file}" sed_command = f"sed -ie 's/@10/@00/g' {hex_file}"
hex_gen_state = os.system(f"docker run -it -v {go_up(self.cocotb_path,4)}:{go_up(self.cocotb_path,4)} efabless/dv:latest sh -c 'cd {test_dir} && {elf_command} && {hex_command} && {sed_command} '") hex_gen_state = os.system(f"docker run -it -v {go_up(self.cocotb_path,4)}:{go_up(self.cocotb_path,4)} efabless/dv:latest sh -c 'cd {test_dir} && {elf_command} && {hex_command} && {sed_command} '")
self.full_terminal.write(os.path.expandvars(elf_command)+"\n"+"\n") self.full_terminal.write("elf file generation command:\n% ")
self.full_terminal.write(os.path.expandvars(hex_command)+"\n"+"\n") self.full_terminal.write(os.path.expandvars(elf_command)+"\n")
self.full_terminal.write(os.path.expandvars(sed_command)+"\n"+"\n") self.full_terminal.write("hex file generation command:\n% ")
self.full_terminal.write(os.path.expandvars(hex_command)+"\n% ")
self.full_terminal.write(os.path.expandvars(sed_command)+"\n")
self.cd_cocotb() self.cd_cocotb()
self.full_terminal.close() self.full_terminal.close()
if hex_gen_state != 0 : if hex_gen_state != 0 :
@ -307,30 +341,44 @@ class RunRegression:
self.unknown_tests +=1 self.unknown_tests +=1
def run_regression(self): def run_regression(self):
threads = list()
for test,sim_types in self.tests.items(): for test,sim_types in self.tests.items():
for sim_type,corners in sim_types.items(): # TODO: add multithreading or multiprocessing here for sim_type,corners in sim_types.items(): # TODO: add multithreading or multiprocessing here
for corner,status in corners.items(): # TODO: add multithreading or multiprocessing here for corner,status in corners.items():
start_time = datetime.now() if iverilog: #threading
self.tests[test][sim_type][corner]["starttime"] = datetime.now().strftime("%H:%M:%S(%a)") # x = threading.Thread(target=self.test_run_function,args=(test,sim_type,corner))
self.tests[test][sim_type][corner]["duration"] = "-" # threads.append(x)
self.tests[test][sim_type][corner]["status"] = "running" # x.start()
self.update_reg_log() # time.sleep(10)
test_run = RunTest(test,sim_type,corner) self.test_run_function(test,sim_type,corner)
self.tests[test][sim_type][corner]["status"] = "done" else:
self.tests[test][sim_type][corner]["endtime"] = datetime.now().strftime("%H:%M:%S(%a)") self.test_run_function(test,sim_type,corner)
self.tests[test][sim_type][corner]["duration"] = ("%.10s" % (datetime.now() - start_time)) for index, thread in enumerate(threads):
self.tests[test][sim_type][corner]["pass"]= test_run.passed thread.join()
if test_run.passed == "passed":
self.passed_tests +=1
elif test_run.passed == "failed":
self.failed_tests +=1
self.unknown_tests -=1
self.update_reg_log()
if coverage: if coverage:
self.generate_cov() self.generate_cov()
#TODO: add send mail here #TODO: add send mail here
def test_run_function(self,test,sim_type,corner):
start_time = datetime.now()
self.tests[test][sim_type][corner]["starttime"] = datetime.now().strftime("%H:%M:%S(%a)")
self.tests[test][sim_type][corner]["duration"] = "-"
self.tests[test][sim_type][corner]["status"] = "running"
self.update_reg_log()
test_run = RunTest(test,sim_type,corner,)
self.tests[test][sim_type][corner]["status"] = "done"
self.tests[test][sim_type][corner]["endtime"] = datetime.now().strftime("%H:%M:%S(%a)")
self.tests[test][sim_type][corner]["duration"] = ("%.10s" % (datetime.now() - start_time))
self.tests[test][sim_type][corner]["pass"]= test_run.passed
if test_run.passed == "passed":
self.passed_tests +=1
elif test_run.passed == "failed":
self.failed_tests +=1
self.unknown_tests -=1
self.update_reg_log()
def generate_cov(self): def generate_cov(self):
os.chdir(f"{self.cocotb_path}/sim/{os.getenv('RUNTAG')}") os.chdir(f"{self.cocotb_path}/sim/{os.getenv('RUNTAG')}")
os.system(f"urg -dir RTL*/*.vdb -format both -show tests -report coverageRTL/") os.system(f"urg -dir RTL*/*.vdb -format both -show tests -report coverageRTL/")