SvPortSim.Verilator.Docker (SvPortSim v0.1.0)

Copy Markdown View Source

Builds a Verilated executable by running Verilator inside Docker.

This module stages SystemVerilog source files and a generated C++ wrapper into a host-side work directory, mounts that directory into a Docker container, and runs the Verilator Docker image with --cc --exe --build.

The expected inputs are:

  • a SystemVerilog top-module name
  • one or more existing SystemVerilog source files
  • an existing C++ wrapper file, typically generated by SvPortSim.Verilator.Wrapper

During compilation, source files are copied into rtl/ under the work directory, and the wrapper file is copied into cpp/. Verilator output is written into obj_dir/, and the expected executable path is obj_dir/V<top_module>.

This module depends on Docker being installed and usable by the current process. By default, compile_executable/4 checks Docker daemon availability before running the build.

The functions in this module do not generate RTL sources or wrapper sources. They only stage existing files and invoke Verilator through Docker.

Summary

Functions

Compiles a Verilated executable by running Verilator inside Docker.

Returns the default host-side Verilator work directory for top_module.

Types

build_result()

@type build_result() :: %{
  top_module: String.t(),
  image: String.t(),
  docker: Path.t(),
  work_dir: Path.t(),
  obj_dir: Path.t(),
  executable: Path.t(),
  command: [String.t()],
  log: String.t()
}

Functions

compile_executable(top_module, source_files, wrapper_cpp, opts \\ [])

@spec compile_executable(term(), term(), term(), keyword()) ::
  {:ok, build_result()} | {:error, term()}

Compiles a Verilated executable by running Verilator inside Docker.

top_module is the SystemVerilog top-module name. It must be a simple identifier accepted by this module: the name must start with an ASCII letter or underscore, followed by ASCII letters, digits, underscores, or dollar signs.

source_files is a non-empty list of existing SystemVerilog source file paths. The basenames of the source files must be unique because the files are staged under the same rtl/ directory in the Docker-mounted workspace.

wrapper_cpp is the path to an existing C++ wrapper source file. The wrapper is staged under cpp/ in the Docker-mounted workspace.

The Docker command mounts the host-side work directory at /work in the container and runs Verilator with:

  • --cc
  • --exe
  • --build
  • -j <make_jobs>
  • --Mdir obj_dir
  • --top-module <top_module>

Extra Verilator arguments, if any, are appended after the fixed Verilator options and before the staged wrapper and source paths.

Options

  • :image - Docker image to use. Defaults to "verilator/verilator:latest".

  • :work_dir - Host-side build directory. Defaults to default_work_dir(top_module). The directory is expanded before use.

  • :docker - Docker executable path. When omitted, the executable is resolved with DockerAvailability.executable/0.

  • :check_docker - Whether to check Docker daemon reachability before preparing the workspace and running Verilator. Defaults to true.

  • :make_jobs - Value passed to Verilator's -j option. Accepts a non-negative integer or a non-empty string. Defaults to 0.

  • :extra_args - Additional Verilator arguments. Must be a list of strings. Defaults to [].

  • :user - Docker user option. Defaults to :current, which attempts to pass the current uid:gid to Docker. Use nil or false to omit --user, or pass a non-empty string such as "1000:1000".

  • :clean - Whether to remove staged rtl/, cpp/, and obj_dir/ directories before preparing the workspace. Defaults to true.

  • :verify_executable - Whether to require the expected executable obj_dir/V<top_module> to exist after Docker finishes successfully. Defaults to true.

Return value

Returns {:ok, build} on success.

The returned build map contains:

  • :top_module - the top-module name
  • :image - the Docker image used for the build
  • :docker - the Docker executable path
  • :work_dir - the host-side work directory
  • :obj_dir - the host-side Verilator output directory
  • :executable - the expected host-side executable path
  • :command - the full Docker command as a list of strings
  • :log - combined standard output and standard error from Docker

Returns {:error, reason} when validation, staging, Docker execution, or executable verification fails.

Common error reasons include:

  • {:invalid_arguments, top_module, source_files, wrapper_cpp} when the required arguments or options do not have the expected types
  • {:invalid_top_module, top_module} when the top-module name is not accepted
  • :empty_source_files when no source files are provided
  • {:invalid_source_files, source_files} when source_files contains a non-string entry
  • {:duplicate_source_basenames, basenames} when multiple source files would collide in the staged rtl/ directory
  • {:source_not_found, path} when a source file does not exist as a regular file
  • {:wrapper_not_found, path} when the wrapper file does not exist as a regular file
  • :docker_not_found when the Docker executable cannot be found
  • {:invalid_docker_executable, docker} when the :docker option is invalid
  • {:docker_unavailable, status, output} when Docker daemon precheck fails
  • {:docker_command_failed, status, output} when a Docker command cannot be executed
  • {:invalid_image, image} when the Docker image option is invalid
  • {:invalid_make_jobs, make_jobs} when the :make_jobs option is invalid
  • {:invalid_extra_args, extra_args} when :extra_args is not a list of strings
  • {:invalid_work_dir, work_dir} when the work directory option is invalid
  • {:mkdir_failed, path, reason} when a workspace directory cannot be created
  • {:clean_failed, path, reason} when workspace cleanup fails
  • {:copy_failed, source, destination, reason} when staging a file fails
  • {:verilator_docker_failed, status, log, command} when Docker exits with a non-zero status while running Verilator
  • {:executable_not_found, executable, log, command} when Docker succeeds but the expected executable is missing
  • {:docker_run_failed, message} when invoking Docker raises an Erlang error

Example

{:ok, build} =
  SvPortSim.Verilator.Docker.compile_executable(
    "Counter",
    ["_build/dev/lib/sv_port_sim/rtl/Counter.sv"],
    "_build/dev/lib/sv_port_sim/cpp/Counter_wrapper.cpp",
    extra_args: ["-Wall"]
  )

build.executable
#=> ".../obj_dir/VCounter"

default_work_dir(top_module)

@spec default_work_dir(String.t()) :: Path.t()

Returns the default host-side Verilator work directory for top_module.

The returned path is application-local and is currently resolved as:

Application.app_dir(:sv_port_sim, Path.join(["verilator", top_module]))

For example, the default work directory for "Counter" is under the application's verilator/Counter directory.

This function only builds the path. It does not validate the top-module name, create the directory, clean previous build artifacts, or run Docker.