import cocotb
import cocotb.log
import interfaces.caravel as caravel
import logging
from cocotb.log import SimTimeContextFilter
from cocotb.log import SimLogFormatter
from tests.common_functions.Timeout import Timeout
from cocotb.triggers import ClockCycles
import yaml
from cocotb_coverage.coverage import coverage_db
"""configure the test log file location and log verbosity
configure the test clock
configure the test timeout
configure whitbox models
start up the test connecting power vdd to the design then reset and disable the CSB bit
return the caravel environmnet with clock and start up
"""
def read_config_file():
config_file = f"{cocotb.plusargs['SIM_DIR']}/configs.yaml".replace('"', "")
with open(config_file) as file:
# The FullLoader parameter handles the conversion from YAML
# scalar values to Python the dictionary format
configs = yaml.load(file, Loader=yaml.FullLoader)
print(configs)
return configs
CLOCK_GLOBAL = 25
class CallCounted:
"""Decorator to determine number of calls for a method"""
def __init__(self, method):
self.method = method
self.counter = 0
def __call__(self, *args, **kwargs):
self.counter += 1
return self.method(*args, **kwargs)
def repot_test(func):
async def wrapper_func(*args, **kwargs):
# configure logging
TESTFULLNAME = cocotb.plusargs["FTESTNAME"]
sim_dir = f"{cocotb.plusargs['SIM_PATH']}/{cocotb.plusargs['TAG']}"
TestName = func.__name__
logger_file = f"{sim_dir}/{TESTFULLNAME}/{TestName}.log".replace('"', "")
cocotb.log.setLevel(logging.INFO)
cocotb.log.error = CallCounted(cocotb.log.error)
cocotb.log.critical = CallCounted(cocotb.log.critical)
cocotb.log.warning = CallCounted(cocotb.log.warning)
handler = logging.FileHandler(logger_file, mode="w")
handler.addFilter(SimTimeContextFilter())
handler.setFormatter(SimLogFormatter())
cocotb.log.addHandler(handler)
# call test
await func(*args, **kwargs)
if "COVERAGE" in cocotb.plusargs or "CHECKERS" in cocotb.plusargs:
coverage_db.export_to_yaml(
filename=f"{sim_dir}/{TESTFULLNAME}/coverage.ylm"
)
# report after finish simulation
msg = f"with ({cocotb.log.critical.counter})criticals ({cocotb.log.error.counter})errors ({cocotb.log.warning.counter})warnings "
if cocotb.log.error.counter > 0 or cocotb.log.critical.counter > 0:
raise cocotb.result.TestComplete(f"Test failed {msg}")
else:
cocotb.log.info(f"Test passed {msg}")
cocotb.log.info(
f'Cycles consumed = {int(cocotb.utils.get_sim_time("ns")/CLOCK_GLOBAL)} recommened timeout = {int(cocotb.utils.get_sim_time("ns")*1.01/CLOCK_GLOBAL)+1} cycles'
)
return wrapper_func
async def max_num_error(num_error, clk):
while True:
await ClockCycles(clk, 1)
if cocotb.log.error.counter + cocotb.log.critical.counter > num_error:
msg = f"Test failed with max number of errors {num_error} ({cocotb.log.critical.counter})criticals ({cocotb.log.error.counter})errors ({cocotb.log.warning.counter})warnings "
raise cocotb.result.TestFailure(msg)