Skip to content

Runners API

Plain RTL and generated components

fpga_verification.sim.runners

intel_component_test_cocotb(project_root, component_file, hdl_toplevel, test_module, source_dirs=(), component_parameters=None, project_directory=None, part=None, quartus_model_files=('220model.v', 'altera_mf.v'), debug=False, generate_only=False, ip_generate_log=None, compile_log=None, retain_generated=False, make_ipx=True, ipx_source_dirs=None, ip_search_paths=(), build_args=None, test_args=None, extra_env=None, apply_simulation_fixes=True)

Generate an Intel component composition and simulate against original RTL.

Generated HDL files that are byte-identical to source files in source_dirs are replaced by those source paths before invoking rtl_test_cocotb. Any remaining generated HDL implements Platform Designer composition wiring. By default it exists only for this call; with generate_only=True its directory is retained and returned for inspection. By default a temporary Platform Designer IP index is generated from source_dirs and passed to ip-generate as a search path. Simulator-specific model fixes are enabled by default; disable them with apply_simulation_fixes=False. Installed Quartus files remain unchanged.

Source code in src/fpga_verification/sim/runners/intel_component.py
def intel_component_test_cocotb(
    project_root,
    component_file,
    hdl_toplevel,
    test_module,
    source_dirs=(),
    component_parameters=None,
    project_directory=None,
    part=None,
    quartus_model_files=("220model.v", "altera_mf.v"),
    debug=False,
    generate_only=False,
    ip_generate_log=None,
    compile_log=None,
    retain_generated=False,
    make_ipx=True,
    ipx_source_dirs=None,
    ip_search_paths=(),
    build_args=None,
    test_args=None,
    extra_env=None,
    apply_simulation_fixes=True,
):
    """Generate an Intel component composition and simulate against original RTL.

    Generated HDL files that are byte-identical to source files in ``source_dirs``
    are replaced by those source paths before invoking ``rtl_test_cocotb``. Any
    remaining generated HDL implements Platform Designer composition wiring. By
    default it exists only for this call; with ``generate_only=True`` its
    directory is retained and returned for inspection. By default a temporary
    Platform Designer IP index is generated from ``source_dirs`` and passed to
    ``ip-generate`` as a search path.
    Simulator-specific model fixes are enabled by default; disable them with
    ``apply_simulation_fixes=False``. Installed Quartus files remain unchanged.
    """
    project_root = Path(project_root)
    component_file = _resolve_path(project_root, component_file)
    if project_directory is None:
        project_directory = project_root
    else:
        project_directory = _resolve_path(project_root, project_directory)

    ip_generate = shutil.which("ip-generate")
    if ip_generate is None:
        raise FileNotFoundError("ip-generate is not available on PATH")

    if component_parameters is None:
        component_parameters = {}

    keep_generated = generate_only or retain_generated

    if keep_generated:
        fixed_output_dir = project_root / f".ip_generate_{hdl_toplevel}"
        _clean_directory(fixed_output_dir)
        generation_context = nullcontext(fixed_output_dir)
    else:
        generation_context = tempfile.TemporaryDirectory(
            prefix=f".ip_generate_{hdl_toplevel}_",
            dir=project_root,
        )

    with generation_context as temporary_dir:
        output_dir = Path(temporary_dir)
        spd_path = output_dir / f"{hdl_toplevel}.spd"
        (output_dir / "submodules").mkdir()

        log_has_content = False
        if ip_generate_log is not None:
            ip_generate_log = Path(ip_generate_log)
            print(f"IP generation log: {ip_generate_log}", flush=True)

        resolved_ip_search_paths = [
            _resolve_path(project_root, path)
            for path in ip_search_paths
        ]

        if make_ipx:
            ipx_path = _make_ipx(
                project_root,
                source_dirs if ipx_source_dirs is None else ipx_source_dirs,
                output_dir,
                log_path=ip_generate_log,
                append_log=log_has_content,
            )
            log_has_content = ipx_path is not None or log_has_content
            if ipx_path is not None:
                resolved_ip_search_paths.insert(0, ipx_path)

        command = [
            ip_generate,
            f"--component-file={component_file}",
            f"--project-directory={project_directory}",
            f"--output-directory={output_dir}",
            "--file-set=SIM_VERILOG",
            f"--output-name={hdl_toplevel}",
            "--remove-qsys-generate-warning",
            f"--report-file=spd:{spd_path}",
        ]
        if part is not None:
            command.append(f"--part={part}")

        if resolved_ip_search_paths:
            search_path = ",".join(str(path) for path in resolved_ip_search_paths)
            command.append(f"--search-path={search_path},$")

        command.extend(
            f"--component-parameter={name}={value}"
            for name, value in component_parameters.items()
        )

        _run_command(
            command,
            cwd=project_root,
            log_path=ip_generate_log,
            append_log=log_has_content,
        )

        generated_sources = _spd_hdl_sources(spd_path)
        spd_path.unlink()
        sources, retained_generated = _use_original_sources(
            project_root,
            source_dirs,
            generated_sources,
        )
        _remove_empty_directories(output_dir)
        model_sources = prepare_simulation_models(
            _quartus_sim_sources(ip_generate, quartus_model_files),
            simulator=os.getenv("SIM", DEFAULT_SIMULATOR),
            output_dir=project_root / "logs" / "simulation_models",
            enabled=apply_simulation_fixes,
        )
        sources = model_sources + sources

        lifecycle = "Retained" if keep_generated else "Temporary"
        generated_hdl_lines = [f"{lifecycle} generated composition HDL:"]
        generated_hdl_lines.extend(f"   {source}" for source in retained_generated)
        if keep_generated:
            generated_hdl_lines.append(f"Generated output directory: {output_dir}")

        if ip_generate_log is None:
            for line in generated_hdl_lines:
                print(line)
        else:
            with ip_generate_log.open(
                "a", encoding="utf-8", errors="replace"
            ) as log:
                print(file=log)
                for line in generated_hdl_lines:
                    print(line, file=log)

        if generate_only:
            print("Generated output directory:", output_dir, flush=True)
            return output_dir

        rtl_test_cocotb(
            project_root=project_root,
            hdl_toplevel=hdl_toplevel,
            test_module=test_module,
            sources=sources,
            debug=debug,
            compile_log=compile_log,
            build_args=build_args,
            test_args=test_args,
            extra_env=extra_env,
        )

run_intel_component_test(*, project_root, component_file, hdl_toplevel, test_module, config=None, component_parameters=None, source_dirs=('../../src', '../../../common'), project_directory='../../..', test_module_env=None, python_paths=('..', '../../../common'), debug=None, argv=None, generate_only=False, retain_generated=False, clean_build=True, enable_questa_acc=False, **kwargs)

Run a standard Intel component cocotb simulation from a small script.

Source code in src/fpga_verification/sim/runners/intel_component.py
def run_intel_component_test(
    *,
    project_root,
    component_file,
    hdl_toplevel,
    test_module,
    config=None,
    component_parameters=None,
    source_dirs=("../../src", "../../../common"),
    project_directory="../../..",
    test_module_env=None,
    python_paths=("..", "../../../common"),
    debug=None,
    argv=None,
    generate_only=False,
    retain_generated=False,
    clean_build=True,
    enable_questa_acc=False,
    **kwargs,
):
    """Run a standard Intel component cocotb simulation from a small script."""
    project_root = Path(project_root)
    debug, sim = prepare_test_run(
        project_root=project_root,
        python_paths=python_paths,
        debug=debug,
        argv=argv,
        clean_build=clean_build,
        enable_questa_acc=enable_questa_acc,
    )

    if config is None:
        component_parameters = (
            {} if component_parameters is None else component_parameters
        )
    else:
        if not hasattr(config, "to_parameters"):
            raise TypeError("config must inherit ComponentConfig")
        resolved_parameters = config.to_parameters()
        if (
            component_parameters is not None
            and dict(component_parameters) != resolved_parameters
        ):
            raise ValueError(
                "component_parameters must match the resolved ComponentConfig"
            )
        component_parameters = resolved_parameters

    if config is not None:
        from ..config import runtime_config_environment

        config_environment = runtime_config_environment(config)
        extra_env = dict(kwargs.pop("extra_env", {}))
        overlap = set(extra_env) & set(config_environment)
        if overlap:
            raise ValueError(
                "extra_env may not override resolved config: "
                + ", ".join(sorted(overlap))
            )
        extra_env.update(config_environment)
        kwargs["extra_env"] = extra_env

    log_dir = project_root / "logs"

    if test_module_env is not None:
        test_module = os.getenv(test_module_env, test_module)

    return intel_component_test_cocotb(
        project_root=project_root,
        component_file=component_file,
        hdl_toplevel=hdl_toplevel,
        test_module=test_module,
        source_dirs=source_dirs,
        component_parameters=component_parameters,
        project_directory=project_directory,
        debug=debug,
        generate_only=generate_only,
        ip_generate_log=log_dir / "ip_generate.log",
        compile_log=log_dir / f"{sim}_compile.log",
        retain_generated=retain_generated,
        **kwargs,
    )

run_rtl_test(*, project_root, hdl_toplevel, test_module, source_dirs=('src',), python_paths=('.',), debug=None, argv=None, clean_build=True, enable_questa_acc=False, test_module_env=None, **kwargs)

Run a standard RTL cocotb simulation from a script or pytest.

Source code in src/fpga_verification/sim/runners/rtl.py
def run_rtl_test(
    *,
    project_root,
    hdl_toplevel,
    test_module,
    source_dirs=("src",),
    python_paths=(".",),
    debug=None,
    argv=None,
    clean_build=True,
    enable_questa_acc=False,
    test_module_env=None,
    **kwargs,
):
    """Run a standard RTL cocotb simulation from a script or pytest."""
    project_root = Path(project_root)
    debug, sim = prepare_test_run(
        project_root=project_root,
        python_paths=python_paths,
        debug=debug,
        argv=argv,
        clean_build=clean_build,
        enable_questa_acc=enable_questa_acc,
    )

    if test_module_env is not None:
        test_module = os.getenv(test_module_env, test_module)

    return rtl_test_cocotb(
        project_root=project_root,
        hdl_toplevel=hdl_toplevel,
        test_module=test_module,
        source_dirs=source_dirs,
        debug=debug,
        compile_log=project_root / "logs" / f"{sim}_compile.log",
        **kwargs,
    )

Platform Designer systems

fpga_verification.sim.platform_designer.platform_test_cocotb(project_root, hdl_toplevel, test_module, debug=False)

Source code in src/fpga_verification/sim/platform_designer.py
def platform_test_cocotb(
        project_root,
        hdl_toplevel,
        test_module,
        debug=False):
    import os

    sim = os.getenv("SIM", DEFAULT_SIMULATOR)

    if sim == "verilator":
        run_verilator(project_root, hdl_toplevel, test_module, debug)
    elif sim == "questa":
        run_questa(project_root, hdl_toplevel, test_module, debug)
    else:
        raise ValueError(f"Unsupported SIM={sim}")