Skip to content

Commit

Permalink
Updating docstrings
Browse files Browse the repository at this point in the history
  • Loading branch information
Jacob Williamson committed Nov 29, 2024
1 parent 82aaa6d commit b81c3f0
Show file tree
Hide file tree
Showing 2 changed files with 104 additions and 16 deletions.
31 changes: 25 additions & 6 deletions common/python/cocotb_simulate_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ def do_assignments(dut, assignments, signals_info):
assign(dut, signal_name, val)


def check_conditions(dut, conditions: Dict[str, int], ts, collect):
def check_conditions(dut, conditions: Dict[str, int], ts):
"""Check value of output signals.
Args:
Expand Down Expand Up @@ -299,6 +299,7 @@ def get_ini_signal_name(name, signals_info):
Args:
name: VHDL signal name.
signals_info: Dictionary containing information about signals.
Returns:
Signal name as it appears in the INI files.
"""
Expand Down Expand Up @@ -363,6 +364,7 @@ def get_extra_signals_info(module, panda_build_dir):
Args:
module: Name of module.
panda_build_dir: Path to autogenerated HDL files
Returns:
Dictionary containing extra signals information.
"""
Expand All @@ -380,6 +382,17 @@ def get_extra_signals_info(module, panda_build_dir):

async def simulate(dut, assignments_schedule, conditions_schedule,
signals_info, collect):
"""Run the simulation according to the schedule found in timing ini.
Args:
dut: cocotb dut object.
assignments_schedule: Schedule for signal assignments.
conditions_schedule: Schedule for checking conditions.
signals_info: Dictionary containing information about signals.
collect: Collect signals expected and actual values when True.
Returns:
Dictionaries containing signal values and timing errors.
"""
last_ts = max(max(assignments_schedule.keys()),
max(conditions_schedule.keys()))
clkedge = RisingEdge(dut.clk_i)
Expand All @@ -397,7 +410,7 @@ async def simulate(dut, assignments_schedule, conditions_schedule,
update_conditions(conditions, conditions_schedule.get(ts, {}),
signals_info)
await ReadOnly()
errors, values[ts] = check_conditions(dut, conditions, ts, collect)
errors, values[ts] = check_conditions(dut, conditions, ts)
if errors:
timing_errors[ts] = errors
await clkedge
Expand All @@ -406,6 +419,12 @@ async def simulate(dut, assignments_schedule, conditions_schedule,


def collect_values(values, test_name):
"""Saves collected signal values to csv and html.
Args:
values: Dictionary of signal values to save.
test_name: Name of test.
"""
filename = f'{test_name.replace(' ', '_').replace('/', '_')}_values'
values_df = pd.DataFrame(values)
values_df = values_df.transpose()
Expand All @@ -415,8 +434,7 @@ def collect_values(values, test_name):


async def section_timing_test(dut, module, test_name, block_ini, timing_ini,
simulator, sim_build_dir, panda_build_dir,
collect=False):
panda_build_dir, collect=True):
"""Perform one test.
Args:
Expand All @@ -425,6 +443,7 @@ async def section_timing_test(dut, module, test_name, block_ini, timing_ini,
test_name: Name of test we are applying to the module.
block_ini: INI file containing information about the module's signals.
timing_ini: INI file containing timing tests.
collect: Collect signals expected and actual values when True.
"""
if block_has_dma(block_ini):
dma_driver = DMADriver(dut, module)
Expand Down Expand Up @@ -471,5 +490,5 @@ async def module_timing_test(dut):
timing_ini = get_timing_ini(module)
if test_name.strip() != '.':
await section_timing_test(
dut, module, test_name, block_ini, timing_ini, simulator,
sim_build_dir, panda_build_dir, collect)
dut, module, test_name, block_ini, timing_ini, panda_build_dir,
collect)
89 changes: 79 additions & 10 deletions common/python/cocotb_timing_test_runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,20 +72,12 @@ def block_has_dma(block_ini):
return block_ini['.'].get('type', '') == 'dma'


def block_is_pcap(block_ini):
"""Check if module is pcap.
Args:
block_ini: INI file containing signals information about a module.
"""
return block_ini['.'].get('type') == 'pcap'


def get_module_build_args(module, panda_build_dir):
"""Get simulation build arguments from a module's test config file.
Args:
module: Name of module.
panda_build_dir: Path to autogenerated HDL files.
Returns:
List of extra build arguments.
"""
Expand Down Expand Up @@ -133,6 +125,9 @@ def get_module_hdl_files(module, top_level, build_dir, panda_build_dir):
Args:
module: Name of module.
top_level: Top level entity of module being tested.
build_dir: Name of simulation build directory.
panda_build_dir: Path to autogenerated HDL files.
Returns:
List of paths to the HDL files.
"""
Expand Down Expand Up @@ -167,6 +162,7 @@ def get_module_top_level(module, panda_build_dir):
Args:
module: Name of module.
panda_build_dir: Path to autogenerated HDL files.
Returns:
Name of top level entity.
"""
Expand Down Expand Up @@ -241,13 +237,29 @@ def summarise_results(results):


def get_simulator_build_args(simulator):
"""Get arguments for the build stage.
Args:
simulator: Name of simulator being used.
Returns:
List of build arguments.
"""
if simulator == 'ghdl':
return ['--std=08', '-fsynopsys', '-Wno-hide']
elif simulator == 'nvc':
return ['--std=2008']


def get_test_args(simulator, build_args, test_name):
"""Get arguments for the test stage.
Args:
simulator: Name of simulator being used.
build_args: Arguments used for the build stage.
test_name: Name of test being carried out.
Returns:
List of test arguments.
"""
test_name = test_name.replace(' ', '_').replace('/', '_')
if simulator == 'ghdl':
return build_args
Expand All @@ -256,13 +268,28 @@ def get_test_args(simulator, build_args, test_name):


def get_elab_args(simulator):
"""Get arguments for the elaboration stage.
Args:
simulator: Name of simulator being used.
Returns:
List of elaboration arguments.
"""
if simulator == 'nvc':
return ['--cover']
else:
return []


def get_plusargs(simulator, test_name):
"""Get plusargs to for the test stage.
Args:
simulator: Name of simulator being used.
test_name: Name of test being carried out.
Returns:
"""
test_name = test_name.replace(' ', '_').replace('/', '_')
vcd_filename = f'{test_name}.vcd'
if simulator == 'ghdl':
Expand All @@ -273,6 +300,15 @@ def get_plusargs(simulator, test_name):


def collect_coverage_file(build_dir, top_level, test_name):
"""Move coverage file to the coverage directory
Args:
build_dir: Simulation build directory.
top_level: Top level entity being tested.
test_name: Name of test being carried out.
Returns:
New file path of the coverage file.
"""
coverage_path = Path(WORKING_DIR / build_dir / 'coverage')
Path(coverage_path).mkdir(exist_ok=True)
old_file_path = Path(WORKING_DIR / build_dir / 'top' /
Expand All @@ -285,6 +321,16 @@ def collect_coverage_file(build_dir, top_level, test_name):


def merge_coverage_data(build_dir, module, file_paths):
"""Merges coverage files from each test to create an overall coverage
report for a module.
Args:
build_dir: Simulation build directory.
module: Name of module.
file_paths: List of paths to coverage files from each test.
Returns:
File path for the coverage report file.
"""
merged_path = Path(WORKING_DIR / build_dir / 'coverage' /
f'merged.{module}.covdb')
command = ['nvc', '--cover-merge', '-o'] + \
Expand All @@ -295,6 +341,13 @@ def merge_coverage_data(build_dir, module, file_paths):


def cleanup_dir(test_name, build_dir):
"""Creates a subdirectory for a test and moves all files generated from
that test into it.
Args:
test_name: Name of test.
build_dir: Simulation build directory.
"""
test_name = test_name.replace(' ', '_').replace('/', '_')
(WORKING_DIR / build_dir / test_name).mkdir(exist_ok=True)
logger.info(f'Putting all files related to "{test_name}" in {str(
Expand All @@ -309,6 +362,12 @@ def cleanup_dir(test_name, build_dir):


def print_errors(failed_tests, build_dir):
"""Print out timing errors.
Args:
failed_tests: List of tests that failed.
build_dir: Simulation build directory.
"""
for test_name in failed_tests:
logger.info(f' See timing errors for "{test_name}" below')
test_name = test_name.replace(' ', '_').replace('/', '_')
Expand All @@ -319,6 +378,11 @@ def print_errors(failed_tests, build_dir):


def print_coverage_data(coverage_report_path):
"""Print coverage report
Args:
coverage_report_path: Path to coverage report file.
"""
print('Code coverage:')
coverage_path = coverage_report_path.parent
command = ['nvc', '--cover-report', '-o', str(coverage_path),
Expand All @@ -327,6 +391,8 @@ def print_coverage_data(coverage_report_path):


def setup_logger():
"""Setup logger to include timing error log level.
"""
timing_error_level = 30
logging.basicConfig(level=logging.DEBUG,
format="%(levelname)s: %(message)s")
Expand All @@ -345,6 +411,9 @@ def test_module(module, test_name=None, simulator='nvc',
module: Name of module.
test_name: Name of specific test to run. If not specified, all tests
for that module will be run.
simulator: Name of simulator to use for simulation.
panda_build_dir: Location of autogenerated HDL files.
collect: If True, collect output signals expected and actual values.
Returns:
Lists of tests that passed and failed respectively, path to coverage.
"""
Expand Down Expand Up @@ -418,7 +487,7 @@ def test_module(module, test_name=None, simulator='nvc',


def get_cocotb_testable_modules():
"""Get list of modules that contain a test config file.
"""Get list of modules that contain a timing.ini file file.
Returns:
List of names of testable modules.
Expand Down

0 comments on commit b81c3f0

Please sign in to comment.